summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-15 04:42:43 +0000
committerxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-15 04:42:43 +0000
commitff41739978fb88dc0334f8bf2546e6ee8eaf5a0e (patch)
tree6df3c69f6d788bc95c80109cee09f1b3881b7391 /media
parentec2e2f697e94600cb16b53f2b9c88664526a4982 (diff)
downloadchromium_src-ff41739978fb88dc0334f8bf2546e6ee8eaf5a0e.zip
chromium_src-ff41739978fb88dc0334f8bf2546e6ee8eaf5a0e.tar.gz
chromium_src-ff41739978fb88dc0334f8bf2546e6ee8eaf5a0e.tar.bz2
Change AesDecryptor::Decrypt to be an asynchronous call.
BUG=125401 TEST=media_tests, media layout tests. Review URL: https://chromiumcodereview.appspot.com/10561014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@146748 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/base/decryptor.h25
-rw-r--r--media/crypto/aes_decryptor.cc28
-rw-r--r--media/crypto/aes_decryptor.h4
-rw-r--r--media/crypto/aes_decryptor_unittest.cc24
-rw-r--r--media/filters/ffmpeg_demuxer_unittest.cc1
-rw-r--r--media/filters/ffmpeg_video_decoder.cc78
-rw-r--r--media/filters/ffmpeg_video_decoder.h23
7 files changed, 135 insertions, 48 deletions
diff --git a/media/base/decryptor.h b/media/base/decryptor.h
index 924f3ac..442c3c6 100644
--- a/media/base/decryptor.h
+++ b/media/base/decryptor.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/basictypes.h"
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "media/base/media_export.h"
@@ -31,6 +32,11 @@ class MEDIA_EXPORT Decryptor {
kDomainError
};
+ enum DecryptStatus {
+ kSuccess, // Decryption successfully completed. Decrypted buffer ready.
+ kError // Error occurred during decryption.
+ };
+
Decryptor() {}
virtual ~Decryptor() {}
@@ -54,11 +60,20 @@ class MEDIA_EXPORT Decryptor {
virtual void CancelKeyRequest(const std::string& key_system,
const std::string& session_id) = 0;
- // Decrypts the |input| buffer, which should not be NULL.
- // Returns a DecoderBuffer with the decrypted data if decryption succeeded.
- // Returns NULL if decryption failed.
- virtual scoped_refptr<DecoderBuffer> Decrypt(
- const scoped_refptr<DecoderBuffer>& input) = 0;
+ // Decrypts the |encrypted| buffer. The decrypt status and decrypted buffer
+ // are returned via the provided callback |decrypt_cb|. The |encrypted| buffer
+ // must not be NULL.
+ //
+ // Note that the callback maybe called synchronously or asynchronously.
+ //
+ // If the returned status is kSuccess, the |encrypted| buffer is successfully
+ // decrypted and the decrypted buffer is ready to be read.
+ // If the returned status is kError, unexpected error has occurred. In this
+ // case the decrypted buffer must be NULL.
+ typedef base::Callback<void(DecryptStatus,
+ const scoped_refptr<DecoderBuffer>&)> DecryptCB;
+ virtual void Decrypt(const scoped_refptr<DecoderBuffer>& encrypted,
+ const DecryptCB& decrypt_cb) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Decryptor);
diff --git a/media/crypto/aes_decryptor.cc b/media/crypto/aes_decryptor.cc
index 129bc33..f677f0d 100644
--- a/media/crypto/aes_decryptor.cc
+++ b/media/crypto/aes_decryptor.cc
@@ -131,8 +131,8 @@ void AesDecryptor::CancelKeyRequest(const std::string& key_system,
const std::string& session_id) {
}
-scoped_refptr<DecoderBuffer> AesDecryptor::Decrypt(
- const scoped_refptr<DecoderBuffer>& encrypted) {
+void AesDecryptor::Decrypt(const scoped_refptr<DecoderBuffer>& encrypted,
+ const DecryptCB& decrypt_cb) {
CHECK(encrypted->GetDecryptConfig());
const uint8* key_id = encrypted->GetDecryptConfig()->key_id();
const int key_id_size = encrypted->GetDecryptConfig()->key_id_size();
@@ -144,21 +144,27 @@ scoped_refptr<DecoderBuffer> AesDecryptor::Decrypt(
{
base::AutoLock auto_lock(key_map_lock_);
KeyMap::const_iterator found = key_map_.find(key_id_string);
- if (found == key_map_.end()) {
- DVLOG(1) << "Could not find a matching key for given key ID.";
- return NULL;
- }
- key = found->second;
+ if (found != key_map_.end())
+ key = found->second;
+ }
+
+ if (!key) {
+ DVLOG(1) << "Could not find a matching key for given key ID.";
+ decrypt_cb.Run(kError, NULL);
+ return;
}
scoped_refptr<DecoderBuffer> decrypted = DecryptData(*encrypted, key);
- if (decrypted) {
- decrypted->SetTimestamp(encrypted->GetTimestamp());
- decrypted->SetDuration(encrypted->GetDuration());
+ if (!decrypted) {
+ DVLOG(1) << "Decryption failed.";
+ decrypt_cb.Run(kError, NULL);
+ return;
}
- return decrypted;
+ decrypted->SetTimestamp(encrypted->GetTimestamp());
+ decrypted->SetDuration(encrypted->GetDuration());
+ decrypt_cb.Run(kSuccess, decrypted);
}
} // namespace media
diff --git a/media/crypto/aes_decryptor.h b/media/crypto/aes_decryptor.h
index 7201052..6d0bf47 100644
--- a/media/crypto/aes_decryptor.h
+++ b/media/crypto/aes_decryptor.h
@@ -42,8 +42,8 @@ class MEDIA_EXPORT AesDecryptor : public Decryptor {
const std::string& session_id) OVERRIDE;
virtual void CancelKeyRequest(const std::string& key_system,
const std::string& session_id) OVERRIDE;
- virtual scoped_refptr<DecoderBuffer> Decrypt(
- const scoped_refptr<DecoderBuffer>& input) OVERRIDE;
+ virtual void Decrypt(const scoped_refptr<DecoderBuffer>& encrypted,
+ const DecryptCB& decrypt_cb) OVERRIDE;
private:
// KeyMap owns the crypto::SymmetricKey* and must delete them when they are
diff --git a/media/crypto/aes_decryptor_unittest.cc b/media/crypto/aes_decryptor_unittest.cc
index 814bd6c..3d9d983 100644
--- a/media/crypto/aes_decryptor_unittest.cc
+++ b/media/crypto/aes_decryptor_unittest.cc
@@ -5,14 +5,17 @@
#include <string>
#include "base/basictypes.h"
+#include "base/bind.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
#include "media/base/mock_filters.h"
#include "media/crypto/aes_decryptor.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::Gt;
+using ::testing::IsNull;
using ::testing::NotNull;
using ::testing::SaveArg;
using ::testing::StrNe;
@@ -49,7 +52,10 @@ static const uint8 kKeyId2[] = {
class AesDecryptorTest : public testing::Test {
public:
- AesDecryptorTest() : decryptor_(&client_) {
+ AesDecryptorTest()
+ : decryptor_(&client_),
+ decrypt_cb_(base::Bind(&AesDecryptorTest::BufferDecrypted,
+ base::Unretained(this))) {
encrypted_data_ = DecoderBuffer::CopyFrom(kEncryptedData,
arraysize(kEncryptedData));
}
@@ -86,9 +92,15 @@ class AesDecryptorTest : public testing::Test {
scoped_ptr<DecryptConfig>(new DecryptConfig(key_id, KeyIdSize)));
}
+ MOCK_METHOD2(BufferDecrypted, void(Decryptor::DecryptStatus,
+ const scoped_refptr<DecoderBuffer>&));
+
void DecryptAndExpectToSucceed() {
- scoped_refptr<DecoderBuffer> decrypted =
- decryptor_.Decrypt(encrypted_data_);
+ scoped_refptr<DecoderBuffer> decrypted;
+ EXPECT_CALL(*this, BufferDecrypted(AesDecryptor::kSuccess, NotNull()))
+ .WillOnce(SaveArg<1>(&decrypted));
+
+ decryptor_.Decrypt(encrypted_data_, decrypt_cb_);
ASSERT_TRUE(decrypted);
int data_length = sizeof(kOriginalData);
ASSERT_EQ(data_length, decrypted->GetDataSize());
@@ -96,15 +108,15 @@ class AesDecryptorTest : public testing::Test {
}
void DecryptAndExpectToFail() {
- scoped_refptr<DecoderBuffer> decrypted =
- decryptor_.Decrypt(encrypted_data_);
- EXPECT_FALSE(decrypted);
+ EXPECT_CALL(*this, BufferDecrypted(AesDecryptor::kError, IsNull()));
+ decryptor_.Decrypt(encrypted_data_, decrypt_cb_);
}
scoped_refptr<DecoderBuffer> encrypted_data_;
MockDecryptorClient client_;
AesDecryptor decryptor_;
std::string session_id_string_;
+ AesDecryptor::DecryptCB decrypt_cb_;
};
TEST_F(AesDecryptorTest, NormalDecryption) {
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index bfb31a2..cb492f5 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -24,7 +24,6 @@ using ::testing::AnyNumber;
using ::testing::DoAll;
using ::testing::InSequence;
using ::testing::Invoke;
-using ::testing::NotNull;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc
index 7e681f8..ed41fc0 100644
--- a/media/filters/ffmpeg_video_decoder.cc
+++ b/media/filters/ffmpeg_video_decoder.cc
@@ -4,13 +4,15 @@
#include "media/filters/ffmpeg_video_decoder.h"
+#include <algorithm>
+#include <string>
+
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/string_number_conversions.h"
#include "media/base/decoder_buffer.h"
-#include "media/base/decryptor.h"
#include "media/base/demuxer_stream.h"
#include "media/base/limits.h"
#include "media/base/media_switches.h"
@@ -275,18 +277,19 @@ void FFmpegVideoDecoder::ReadFromDemuxerStream() {
DCHECK_NE(state_, kDecodeFinished);
DCHECK(!read_cb_.is_null());
- demuxer_stream_->Read(base::Bind(&FFmpegVideoDecoder::DecodeBuffer, this));
+ demuxer_stream_->Read(base::Bind(&FFmpegVideoDecoder::DecryptOrDecodeBuffer,
+ this));
}
-void FFmpegVideoDecoder::DecodeBuffer(
+void FFmpegVideoDecoder::DecryptOrDecodeBuffer(
const scoped_refptr<DecoderBuffer>& buffer) {
// TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read
// callback on the same execution stack so we can get rid of forced task post.
message_loop_->PostTask(FROM_HERE, base::Bind(
- &FFmpegVideoDecoder::DoDecodeBuffer, this, buffer));
+ &FFmpegVideoDecoder::DoDecryptOrDecodeBuffer, this, buffer));
}
-void FFmpegVideoDecoder::DoDecodeBuffer(
+void FFmpegVideoDecoder::DoDecryptOrDecodeBuffer(
const scoped_refptr<DecoderBuffer>& buffer) {
DCHECK_EQ(MessageLoop::current(), message_loop_);
DCHECK_NE(state_, kUninitialized);
@@ -304,6 +307,58 @@ void FFmpegVideoDecoder::DoDecodeBuffer(
return;
}
+ if (buffer->GetDecryptConfig() && buffer->GetDataSize()) {
+ decryptor_->Decrypt(buffer,
+ base::Bind(&FFmpegVideoDecoder::BufferDecrypted, this));
+ return;
+ }
+
+ DecodeBuffer(buffer);
+}
+
+void FFmpegVideoDecoder::BufferDecrypted(
+ Decryptor::DecryptStatus decrypt_status,
+ const scoped_refptr<DecoderBuffer>& buffer) {
+ message_loop_->PostTask(FROM_HERE, base::Bind(
+ &FFmpegVideoDecoder::DoBufferDecrypted, this, decrypt_status, buffer));
+}
+
+void FFmpegVideoDecoder::DoBufferDecrypted(
+ Decryptor::DecryptStatus decrypt_status,
+ const scoped_refptr<DecoderBuffer>& buffer) {
+ DCHECK_EQ(MessageLoop::current(), message_loop_);
+ DCHECK_NE(state_, kUninitialized);
+ DCHECK_NE(state_, kDecodeFinished);
+ DCHECK(!read_cb_.is_null());
+
+ if (!reset_cb_.is_null()) {
+ DeliverFrame(NULL);
+ DoReset();
+ return;
+ }
+
+ if (decrypt_status == Decryptor::kError) {
+ state_ = kDecodeFinished;
+ base::ResetAndReturn(&read_cb_).Run(kDecryptError, NULL);
+ return;
+ }
+
+ DCHECK_EQ(Decryptor::kSuccess, decrypt_status);
+ DCHECK(buffer);
+ DCHECK(buffer->GetDataSize());
+ DCHECK(!buffer->GetDecryptConfig());
+ DecodeBuffer(buffer);
+}
+
+void FFmpegVideoDecoder::DecodeBuffer(
+ const scoped_refptr<DecoderBuffer>& buffer) {
+ DCHECK_EQ(MessageLoop::current(), message_loop_);
+ DCHECK_NE(state_, kUninitialized);
+ DCHECK_NE(state_, kDecodeFinished);
+ DCHECK(reset_cb_.is_null());
+ DCHECK(!read_cb_.is_null());
+ DCHECK(buffer);
+
// During decode, because reads are issued asynchronously, it is possible to
// receive multiple end of stream buffers since each read is acked. When the
// first end of stream buffer is read, FFmpeg may still have frames queued
@@ -334,19 +389,8 @@ void FFmpegVideoDecoder::DoDecodeBuffer(
state_ = kFlushCodec;
}
- scoped_refptr<DecoderBuffer> unencrypted_buffer = buffer;
- if (buffer->GetDecryptConfig() && buffer->GetDataSize()) {
- unencrypted_buffer = decryptor_->Decrypt(buffer);
-
- if (!unencrypted_buffer || !unencrypted_buffer->GetDataSize()) {
- state_ = kDecodeFinished;
- base::ResetAndReturn(&read_cb_).Run(kDecryptError, NULL);
- return;
- }
- }
-
scoped_refptr<VideoFrame> video_frame;
- if (!Decode(unencrypted_buffer, &video_frame)) {
+ if (!Decode(buffer, &video_frame)) {
state_ = kDecodeFinished;
base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
return;
diff --git a/media/filters/ffmpeg_video_decoder.h b/media/filters/ffmpeg_video_decoder.h
index 3bfcf3f..0f07755 100644
--- a/media/filters/ffmpeg_video_decoder.h
+++ b/media/filters/ffmpeg_video_decoder.h
@@ -5,10 +5,9 @@
#ifndef MEDIA_FILTERS_FFMPEG_VIDEO_DECODER_H_
#define MEDIA_FILTERS_FFMPEG_VIDEO_DECODER_H_
-#include <deque>
-
#include "base/callback.h"
#include "base/memory/ref_counted.h"
+#include "media/base/decryptor.h"
#include "media/base/video_decoder.h"
class MessageLoop;
@@ -19,7 +18,6 @@ struct AVFrame;
namespace media {
class DecoderBuffer;
-class Decryptor;
class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder {
public:
@@ -59,10 +57,23 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder {
// Reads from the demuxer stream with corresponding callback method.
void ReadFromDemuxerStream();
- void DecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer);
+ void DecryptOrDecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer);
+
+ // Carries out the buffer processing operation scheduled by
+ // DecryptOrDecodeBuffer().
+ void DoDecryptOrDecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer);
- // Carries out the decoding operation scheduled by DecodeBuffer().
- void DoDecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer);
+ // Callback called by the decryptor to deliver decrypted data buffer and
+ // reporting decrypt status. This callback could be called synchronously or
+ // asynchronously.
+ void BufferDecrypted(Decryptor::DecryptStatus decrypt_status,
+ const scoped_refptr<DecoderBuffer>& buffer);
+
+ // Carries out the operation scheduled by BufferDecrypted().
+ void DoBufferDecrypted(Decryptor::DecryptStatus decrypt_status,
+ const scoped_refptr<DecoderBuffer>& buffer);
+
+ void DecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer);
bool Decode(const scoped_refptr<DecoderBuffer>& buffer,
scoped_refptr<VideoFrame>* video_frame);