Skip to content

Commit

Permalink
Plumb support for audio sample formats.
Browse files Browse the repository at this point in the history
- Introduces a new PP_DecryptedSampleInfo structure which
contains the AudioFormat for use when delivering samples.
- Plumbs the structure through to ContentDecryptorDelegate.
- Extends the ContentDecryptorDelegate code to handle planar
data.
- Cleans up FFmpegCdmAudioDecoder to remove 3 memcpy's in the
common case (1 decode per packet) and 2 in the uncommon (> 1
decode per packet).

BUG=169105
TEST=eme browsertests

Review URL: https://codereview.chromium.org/26956002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@230250 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
dalecurtis@chromium.org committed Oct 22, 2013
1 parent a42ac27 commit 455e7d8
Show file tree
Hide file tree
Showing 21 changed files with 334 additions and 149 deletions.
62 changes: 48 additions & 14 deletions content/renderer/pepper/content_decryptor_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,27 @@ PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType(
}
}

media::SampleFormat PpDecryptedSampleFormatToMediaSampleFormat(
PP_DecryptedSampleFormat result) {
switch (result) {
case PP_DECRYPTEDSAMPLEFORMAT_U8:
return media::kSampleFormatU8;
case PP_DECRYPTEDSAMPLEFORMAT_S16:
return media::kSampleFormatS16;
case PP_DECRYPTEDSAMPLEFORMAT_S32:
return media::kSampleFormatS32;
case PP_DECRYPTEDSAMPLEFORMAT_F32:
return media::kSampleFormatF32;
case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16:
return media::kSampleFormatPlanarS16;
case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32:
return media::kSampleFormatPlanarF32;
default:
NOTREACHED();
return media::kUnknownSampleFormat;
}
}

} // namespace

ContentDecryptorDelegate::ContentDecryptorDelegate(
Expand All @@ -232,10 +253,8 @@ ContentDecryptorDelegate::ContentDecryptorDelegate(
pending_video_decoder_init_request_id_(0),
pending_audio_decode_request_id_(0),
pending_video_decode_request_id_(0),
audio_sample_format_(media::kUnknownSampleFormat),
audio_samples_per_second_(0),
audio_channel_count_(0),
audio_bytes_per_frame_(0),
weak_ptr_factory_(this) {
weak_this_ = weak_ptr_factory_.GetWeakPtr();
}
Expand Down Expand Up @@ -405,10 +424,8 @@ bool ContentDecryptorDelegate::InitializeAudioDecoder(
pp_decoder_config.samples_per_second = decoder_config.samples_per_second();
pp_decoder_config.request_id = next_decryption_request_id_++;

audio_sample_format_ = decoder_config.sample_format();
audio_samples_per_second_ = pp_decoder_config.samples_per_second;
audio_channel_count_ = pp_decoder_config.channel_count;
audio_bytes_per_frame_ = decoder_config.bytes_per_frame();

scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
if (!MakeBufferResource(pp_instance_,
Expand Down Expand Up @@ -852,12 +869,12 @@ void ContentDecryptorDelegate::DeliverFrame(

void ContentDecryptorDelegate::DeliverSamples(
PP_Resource audio_frames,
const PP_DecryptedBlockInfo* block_info) {
DCHECK(block_info);
const PP_DecryptedSampleInfo* sample_info) {
DCHECK(sample_info);

FreeBuffer(block_info->tracking_info.buffer_id);
FreeBuffer(sample_info->tracking_info.buffer_id);

const uint32_t request_id = block_info->tracking_info.request_id;
const uint32_t request_id = sample_info->tracking_info.request_id;
DVLOG(2) << "DeliverSamples() - request_id: " << request_id;

// If the request ID is not valid or does not match what's saved, do nothing.
Expand All @@ -874,15 +891,19 @@ void ContentDecryptorDelegate::DeliverSamples(
const media::Decryptor::AudioBuffers empty_frames;

media::Decryptor::Status status =
PpDecryptResultToMediaDecryptorStatus(block_info->result);
PpDecryptResultToMediaDecryptorStatus(sample_info->result);
if (status != media::Decryptor::kSuccess) {
audio_decode_cb.Run(status, empty_frames);
return;
}

media::SampleFormat sample_format =
PpDecryptedSampleFormatToMediaSampleFormat(sample_info->format);

media::Decryptor::AudioBuffers audio_frame_list;
if (!DeserializeAudioFrames(audio_frames,
block_info->data_size,
sample_info->data_size,
sample_format,
&audio_frame_list)) {
NOTREACHED() << "CDM did not serialize the buffer correctly.";
audio_decode_cb.Run(media::Decryptor::kError, empty_frames);
Expand Down Expand Up @@ -995,6 +1016,7 @@ void ContentDecryptorDelegate::SetBufferToFreeInTrackingInfo(
bool ContentDecryptorDelegate::DeserializeAudioFrames(
PP_Resource audio_frames,
size_t data_size,
media::SampleFormat sample_format,
media::Decryptor::AudioBuffers* frames) {
DCHECK(frames);
EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true);
Expand All @@ -1012,6 +1034,13 @@ bool ContentDecryptorDelegate::DeserializeAudioFrames(
const uint8* cur = static_cast<uint8*>(mapper.data());
size_t bytes_left = data_size;

const int audio_bytes_per_frame =
media::SampleFormatToBytesPerChannel(sample_format) *
audio_channel_count_;

// Allocate space for the channel pointers given to AudioBuffer.
std::vector<const uint8*> channel_ptrs(
audio_channel_count_, static_cast<const uint8*>(NULL));
do {
int64 timestamp = 0;
int64 frame_size = -1;
Expand All @@ -1034,13 +1063,18 @@ bool ContentDecryptorDelegate::DeserializeAudioFrames(
return false;
}

const uint8* data[] = {cur};
int frame_count = frame_size / audio_bytes_per_frame_;
// Setup channel pointers. AudioBuffer::CopyFrom() will only use the first
// one in the case of interleaved data.
const int size_per_channel = frame_size / audio_channel_count_;
for (int i = 0; i < audio_channel_count_; ++i)
channel_ptrs[i] = cur + i * size_per_channel;

const int frame_count = frame_size / audio_bytes_per_frame;
scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom(
audio_sample_format_,
sample_format,
audio_channel_count_,
frame_count,
data,
&channel_ptrs[0],
base::TimeDelta::FromMicroseconds(timestamp),
base::TimeDelta::FromMicroseconds(audio_samples_per_second_ /
frame_count));
Expand Down
5 changes: 2 additions & 3 deletions content/renderer/pepper/content_decryptor_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class ContentDecryptorDelegate {
void DeliverFrame(PP_Resource decrypted_frame,
const PP_DecryptedFrameInfo* frame_info);
void DeliverSamples(PP_Resource audio_frames,
const PP_DecryptedBlockInfo* block_info);
const PP_DecryptedSampleInfo* sample_info);

private:
// Cancels the pending decrypt-and-decode callback for |stream_type|.
Expand Down Expand Up @@ -132,6 +132,7 @@ class ContentDecryptorDelegate {
// buffers in |frames|. Returns true upon success.
bool DeserializeAudioFrames(PP_Resource audio_frames,
size_t data_size,
media::SampleFormat sample_format,
media::Decryptor::AudioBuffers* frames);

const PP_Instance pp_instance_;
Expand Down Expand Up @@ -178,10 +179,8 @@ class ContentDecryptorDelegate {
std::queue<uint32_t> free_buffers_;

// Keep track of audio parameters.
media::SampleFormat audio_sample_format_;
int audio_samples_per_second_;
int audio_channel_count_;
int audio_bytes_per_frame_;

base::WeakPtr<ContentDecryptorDelegate> weak_this_;
base::WeakPtrFactory<ContentDecryptorDelegate> weak_ptr_factory_;
Expand Down
4 changes: 2 additions & 2 deletions content/renderer/pepper/pepper_plugin_instance_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2276,8 +2276,8 @@ void PepperPluginInstanceImpl::DeliverFrame(
void PepperPluginInstanceImpl::DeliverSamples(
PP_Instance instance,
PP_Resource audio_frames,
const PP_DecryptedBlockInfo* block_info) {
content_decryptor_delegate_->DeliverSamples(audio_frames, block_info);
const PP_DecryptedSampleInfo* sample_info) {
content_decryptor_delegate_->DeliverSamples(audio_frames, sample_info);
}

void PepperPluginInstanceImpl::NumberOfFindResultsChanged(
Expand Down
7 changes: 4 additions & 3 deletions content/renderer/pepper/pepper_plugin_instance_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -470,9 +470,10 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
virtual void DeliverFrame(PP_Instance instance,
PP_Resource decrypted_frame,
const PP_DecryptedFrameInfo* frame_info) OVERRIDE;
virtual void DeliverSamples(PP_Instance instance,
PP_Resource audio_frames,
const PP_DecryptedBlockInfo* block_info) OVERRIDE;
virtual void DeliverSamples(
PP_Instance instance,
PP_Resource audio_frames,
const PP_DecryptedSampleInfo* sample_info) OVERRIDE;

// Reset this instance as proxied. Assigns the instance a new module, resets
// cached interfaces to point to the out-of-process proxy and re-sends
Expand Down
44 changes: 33 additions & 11 deletions media/cdm/ppapi/cdm_adapter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,26 @@ PP_DecryptedFrameFormat CdmVideoFormatToPpDecryptedFrameFormat(
}
}

PP_DecryptedSampleFormat CdmAudioFormatToPpDecryptedSampleFormat(
cdm::AudioFormat format) {
switch (format) {
case cdm::kAudioFormatU8:
return PP_DECRYPTEDSAMPLEFORMAT_U8;
case cdm::kAudioFormatS16:
return PP_DECRYPTEDSAMPLEFORMAT_S16;
case cdm::kAudioFormatS32:
return PP_DECRYPTEDSAMPLEFORMAT_S32;
case cdm::kAudioFormatF32:
return PP_DECRYPTEDSAMPLEFORMAT_F32;
case cdm::kAudioFormatPlanarS16:
return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16;
case cdm::kAudioFormatPlanarF32:
return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32;
default:
return PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN;
}
}

cdm::AudioDecoderConfig::AudioCodec PpAudioCodecToCdmAudioCodec(
PP_AudioCodec codec) {
switch (codec) {
Expand Down Expand Up @@ -675,30 +695,32 @@ void CdmAdapter::DeliverSamples(int32_t result,
const PP_DecryptTrackingInfo& tracking_info) {
PP_DCHECK(result == PP_OK);

PP_DecryptedBlockInfo decrypted_block_info;
decrypted_block_info.tracking_info = tracking_info;
decrypted_block_info.tracking_info.timestamp = 0;
decrypted_block_info.tracking_info.buffer_id = 0;
decrypted_block_info.data_size = 0;
decrypted_block_info.result = CdmStatusToPpDecryptResult(status);
PP_DecryptedSampleInfo decrypted_sample_info;
decrypted_sample_info.tracking_info = tracking_info;
decrypted_sample_info.tracking_info.timestamp = 0;
decrypted_sample_info.tracking_info.buffer_id = 0;
decrypted_sample_info.data_size = 0;
decrypted_sample_info.result = CdmStatusToPpDecryptResult(status);

pp::Buffer_Dev buffer;

if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) {
if (decrypted_sample_info.result == PP_DECRYPTRESULT_SUCCESS) {
PP_DCHECK(audio_frames.get() && audio_frames->FrameBuffer());
if (!audio_frames.get() || !audio_frames->FrameBuffer()) {
PP_NOTREACHED();
decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
decrypted_sample_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
} else {
PpbBuffer* ppb_buffer =
static_cast<PpbBuffer*>(audio_frames->FrameBuffer());
buffer = ppb_buffer->buffer_dev();
decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
decrypted_block_info.data_size = ppb_buffer->Size();
decrypted_sample_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
decrypted_sample_info.data_size = ppb_buffer->Size();
decrypted_sample_info.format =
CdmAudioFormatToPpDecryptedSampleFormat(audio_frames->Format());
}
}

pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_block_info);
pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_sample_info);
}

bool CdmAdapter::IsValidVideoFrame(const LinkedVideoFrame& video_frame) {
Expand Down
8 changes: 4 additions & 4 deletions media/cdm/ppapi/cdm_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,10 @@ CdmWrapper* CdmWrapper::Create(const char* key_system,
}

// When updating the CdmAdapter, ensure you've updated the CdmWrapper to contain
// stub implementations for new or modified methods which the older CDM
// interface does not have.
COMPILE_ASSERT(cdm::ContentDecryptionModule_2::kVersion ==
cdm::ContentDecryptionModule::kVersion,
// stub implementations for new or modified methods that the older CDM interface
// does not have.
COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion ==
cdm::ContentDecryptionModule_2::kVersion,
ensure_cdm_wrapper_templates_have_old_version_support);

} // namespace media
Expand Down
16 changes: 13 additions & 3 deletions media/cdm/ppapi/clear_key_cdm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,11 @@ void* CreateCdmInstance(
return NULL;
}

if (cdm_interface_version != cdm::ContentDecryptionModule_1::kVersion)
if (cdm_interface_version != cdm::ContentDecryptionModule_2::kVersion)
return NULL;

cdm::Host* host = static_cast<cdm::Host*>(
get_cdm_host_func(cdm::ContentDecryptionModule_1::kVersion, user_data));
get_cdm_host_func(cdm::ContentDecryptionModule_2::kVersion, user_data));
if (!host)
return NULL;

Expand Down Expand Up @@ -417,7 +417,7 @@ cdm::Status ClearKeyCdm::DecryptAndDecodeFrame(

cdm::Status ClearKeyCdm::DecryptAndDecodeSamples(
const cdm::InputBuffer& encrypted_buffer,
cdm::AudioFrames_1* audio_frames) {
cdm::AudioFrames* audio_frames) {
DVLOG(1) << "DecryptAndDecodeSamples()";

scoped_refptr<media::DecoderBuffer> buffer;
Expand Down Expand Up @@ -500,6 +500,16 @@ cdm::Status ClearKeyCdm::DecryptToMediaDecoderBuffer(
return cdm::kSuccess;
}

void ClearKeyCdm::OnPlatformChallengeResponse(
const cdm::PlatformChallengeResponse& response) {
NOTIMPLEMENTED();
}

void ClearKeyCdm::OnQueryOutputProtectionStatus(
uint32_t link_mask, uint32_t output_protection_mask) {
NOTIMPLEMENTED();
};

#if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
int64 ClearKeyCdm::CurrentTimeStampInMicroseconds() const {
return output_timestamp_base_in_microseconds_ +
Expand Down
8 changes: 6 additions & 2 deletions media/cdm/ppapi/clear_key_cdm.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class DecoderBuffer;
class FFmpegCdmAudioDecoder;

// Clear key implementation of the cdm::ContentDecryptionModule interface.
class ClearKeyCdm : public cdm::ContentDecryptionModule_1 {
class ClearKeyCdm : public cdm::ContentDecryptionModule_2 {
public:
explicit ClearKeyCdm(cdm::Host* host);
virtual ~ClearKeyCdm();
Expand Down Expand Up @@ -56,8 +56,12 @@ class ClearKeyCdm : public cdm::ContentDecryptionModule_1 {
cdm::VideoFrame* video_frame) OVERRIDE;
virtual cdm::Status DecryptAndDecodeSamples(
const cdm::InputBuffer& encrypted_buffer,
cdm::AudioFrames_1* audio_frames) OVERRIDE;
cdm::AudioFrames* audio_frames) OVERRIDE;
virtual void Destroy() OVERRIDE;
virtual void OnPlatformChallengeResponse(
const cdm::PlatformChallengeResponse& response) OVERRIDE;
virtual void OnQueryOutputProtectionStatus(
uint32_t link_mask, uint32_t output_protection_mask) OVERRIDE;

private:
// TODO(xhwang): After we removed DecryptorClient. We probably can also remove
Expand Down
Loading

0 comments on commit 455e7d8

Please sign in to comment.