diff --git a/content/renderer/pepper/content_decryptor_delegate.cc b/content/renderer/pepper/content_decryptor_delegate.cc index 3c9dce26496cdb..7ebceb1b2738fa 100644 --- a/content/renderer/pepper/content_decryptor_delegate.cc +++ b/content/renderer/pepper/content_decryptor_delegate.cc @@ -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( @@ -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(); } @@ -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 extra_data_resource; if (!MakeBufferResource(pp_instance_, @@ -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. @@ -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); @@ -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 enter(audio_frames, true); @@ -1012,6 +1034,13 @@ bool ContentDecryptorDelegate::DeserializeAudioFrames( const uint8* cur = static_cast(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 channel_ptrs( + audio_channel_count_, static_cast(NULL)); do { int64 timestamp = 0; int64 frame_size = -1; @@ -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 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)); diff --git a/content/renderer/pepper/content_decryptor_delegate.h b/content/renderer/pepper/content_decryptor_delegate.h index 26989face35ea2..efa75867bdaa15 100644 --- a/content/renderer/pepper/content_decryptor_delegate.h +++ b/content/renderer/pepper/content_decryptor_delegate.h @@ -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|. @@ -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_; @@ -178,10 +179,8 @@ class ContentDecryptorDelegate { std::queue 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 weak_this_; base::WeakPtrFactory weak_ptr_factory_; diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc index 3973bb8bb451f2..9282fcb1b67fc5 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc @@ -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( diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.h b/content/renderer/pepper/pepper_plugin_instance_impl.h index 4398fd91178722..f28cd44fa1a3de 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.h +++ b/content/renderer/pepper/pepper_plugin_instance_impl.h @@ -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 diff --git a/media/cdm/ppapi/cdm_adapter.cc b/media/cdm/ppapi/cdm_adapter.cc index 6814a5ef5faa67..92bb3264bc79ec 100644 --- a/media/cdm/ppapi/cdm_adapter.cc +++ b/media/cdm/ppapi/cdm_adapter.cc @@ -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) { @@ -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(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) { diff --git a/media/cdm/ppapi/cdm_wrapper.h b/media/cdm/ppapi/cdm_wrapper.h index e660c25a47922d..370eecc6075929 100644 --- a/media/cdm/ppapi/cdm_wrapper.h +++ b/media/cdm/ppapi/cdm_wrapper.h @@ -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 diff --git a/media/cdm/ppapi/clear_key_cdm.cc b/media/cdm/ppapi/clear_key_cdm.cc index d73250010491a0..071b2b35e31b1a 100644 --- a/media/cdm/ppapi/clear_key_cdm.cc +++ b/media/cdm/ppapi/clear_key_cdm.cc @@ -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( - get_cdm_host_func(cdm::ContentDecryptionModule_1::kVersion, user_data)); + get_cdm_host_func(cdm::ContentDecryptionModule_2::kVersion, user_data)); if (!host) return NULL; @@ -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 buffer; @@ -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_ + diff --git a/media/cdm/ppapi/clear_key_cdm.h b/media/cdm/ppapi/clear_key_cdm.h index c77e4b4102932a..a0d951c0124901 100644 --- a/media/cdm/ppapi/clear_key_cdm.h +++ b/media/cdm/ppapi/clear_key_cdm.h @@ -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(); @@ -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 diff --git a/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.cc b/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.cc index 3e2ca6504bb9ad..97d04e867cf9bc 100644 --- a/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.cc +++ b/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.cc @@ -80,10 +80,59 @@ static void CdmAudioDecoderConfigToAVCodecContext( } } +static cdm::AudioFormat AVSampleFormatToCdmAudioFormat( + AVSampleFormat sample_format) { + switch (sample_format) { + case AV_SAMPLE_FMT_U8: + return cdm::kAudioFormatU8; + case AV_SAMPLE_FMT_S16: + return cdm::kAudioFormatS16; + case AV_SAMPLE_FMT_S32: + return cdm::kAudioFormatS32; + case AV_SAMPLE_FMT_FLT: + return cdm::kAudioFormatF32; + case AV_SAMPLE_FMT_S16P: + return cdm::kAudioFormatPlanarS16; + case AV_SAMPLE_FMT_FLTP: + return cdm::kAudioFormatPlanarF32; + default: + DVLOG(1) << "Unknown AVSampleFormat: " << sample_format; + } + return cdm::kUnknownAudioFormat; +} + +static void CopySamples(cdm::AudioFormat cdm_format, + int decoded_audio_size, + const AVFrame& av_frame, + uint8_t* output_buffer) { + switch (cdm_format) { + case cdm::kAudioFormatU8: + case cdm::kAudioFormatS16: + case cdm::kAudioFormatS32: + case cdm::kAudioFormatF32: + memcpy(output_buffer, av_frame.data[0], decoded_audio_size); + break; + case cdm::kAudioFormatPlanarS16: + case cdm::kAudioFormatPlanarF32: { + const int decoded_size_per_channel = + decoded_audio_size / av_frame.channels; + for (int i = 0; i < av_frame.channels; ++i) { + memcpy(output_buffer, + av_frame.extended_data[i], + decoded_size_per_channel); + output_buffer += decoded_size_per_channel; + } + break; + } + default: + NOTREACHED() << "Unsupported CDM Audio Format!"; + memset(output_buffer, 0, decoded_audio_size); + } +} + FFmpegCdmAudioDecoder::FFmpegCdmAudioDecoder(cdm::Host* host) : is_initialized_(false), host_(host), - bits_per_channel_(0), samples_per_second_(0), channels_(0), av_sample_format_(0), @@ -98,7 +147,6 @@ FFmpegCdmAudioDecoder::~FFmpegCdmAudioDecoder() { bool FFmpegCdmAudioDecoder::Initialize(const cdm::AudioDecoderConfig& config) { DVLOG(1) << "Initialize()"; - if (!IsValidConfig(config)) { LOG(ERROR) << "Initialize(): invalid audio decoder configuration."; return false; @@ -131,27 +179,12 @@ bool FFmpegCdmAudioDecoder::Initialize(const cdm::AudioDecoderConfig& config) { return false; } - // Some codecs will only output float data, so we need to convert to integer - // before returning the decoded buffer. - if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP || - codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) { - // Preallocate the AudioBus for float conversions. We can treat interleaved - // float data as a single planar channel since our output is expected in an - // interleaved format anyways. - int channels = codec_context_->channels; - if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) - channels = 1; - converter_bus_ = AudioBus::CreateWrapper(channels); - } - // Success! av_frame_.reset(avcodec_alloc_frame()); - bits_per_channel_ = config.bits_per_channel; samples_per_second_ = config.samples_per_second; - bytes_per_frame_ = codec_context_->channels * bits_per_channel_ / 8; + bytes_per_frame_ = codec_context_->channels * config.bits_per_channel / 8; output_timestamp_helper_.reset( new AudioTimestampHelper(config.samples_per_second)); - serialized_audio_frames_.reserve(bytes_per_frame_ * samples_per_second_); is_initialized_ = true; // Store initial values to guard against midstream configuration changes. @@ -190,7 +223,7 @@ cdm::Status FFmpegCdmAudioDecoder::DecodeBuffer( const uint8_t* compressed_buffer, int32_t compressed_buffer_size, int64_t input_timestamp, - cdm::AudioFrames_1* decoded_frames) { + cdm::AudioFrames* decoded_frames) { DVLOG(1) << "DecodeBuffer()"; const bool is_end_of_stream = !compressed_buffer; base::TimeDelta timestamp = @@ -226,6 +259,12 @@ cdm::Status FFmpegCdmAudioDecoder::DecodeBuffer( packet.data = const_cast(compressed_buffer); packet.size = compressed_buffer_size; + // Tell the CDM what AudioFormat we're using. + const cdm::AudioFormat cdm_format = AVSampleFormatToCdmAudioFormat( + static_cast(av_sample_format_)); + DCHECK_NE(cdm_format, cdm::kUnknownAudioFormat); + decoded_frames->SetFormat(cdm_format); + // Each audio packet may contain several frames, so we must call the decoder // until we've exhausted the packet. Regardless of the packet size we always // want to hand it to the decoder at least once, otherwise we would end up @@ -289,76 +328,63 @@ cdm::Status FFmpegCdmAudioDecoder::DecodeBuffer( decoded_audio_size = av_samples_get_buffer_size( NULL, codec_context_->channels, av_frame_->nb_samples, codec_context_->sample_fmt, 1); - // If we're decoding into float, adjust audio size. - if (converter_bus_ && bits_per_channel_ / 8 != sizeof(float)) { - DCHECK(codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT || - codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP); - decoded_audio_size *= - static_cast(bits_per_channel_ / 8) / sizeof(float); - } } - int start_sample = 0; if (decoded_audio_size > 0 && output_bytes_to_drop_ > 0) { DCHECK_EQ(decoded_audio_size % bytes_per_frame_, 0) << "Decoder didn't output full frames"; int dropped_size = std::min(decoded_audio_size, output_bytes_to_drop_); - start_sample = dropped_size / bytes_per_frame_; decoded_audio_size -= dropped_size; output_bytes_to_drop_ -= dropped_size; } - scoped_refptr output; if (decoded_audio_size > 0) { DCHECK_EQ(decoded_audio_size % bytes_per_frame_, 0) << "Decoder didn't output full frames"; - // Convert float data using an AudioBus. - if (converter_bus_) { - // Setup the AudioBus as a wrapper of the AVFrame data and then use - // AudioBus::ToInterleaved() to convert the data as necessary. - int skip_frames = start_sample; - int total_frames = av_frame_->nb_samples; - int frames_to_interleave = decoded_audio_size / bytes_per_frame_; - if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) { - DCHECK_EQ(converter_bus_->channels(), 1); - total_frames *= codec_context_->channels; - skip_frames *= codec_context_->channels; - frames_to_interleave *= codec_context_->channels; - } + base::TimeDelta output_timestamp = + output_timestamp_helper_->GetTimestamp(); + output_timestamp_helper_->AddFrames(decoded_audio_size / + bytes_per_frame_); - converter_bus_->set_frames(total_frames); - for (int i = 0; i < converter_bus_->channels(); ++i) { - converter_bus_->SetChannelData(i, reinterpret_cast( - av_frame_->extended_data[i])); + // If we've exhausted the packet in the first decode we can write directly + // into the frame buffer instead of a multistep serialization approach. + if (serialized_audio_frames_.empty() && !packet.size) { + const uint32_t buffer_size = decoded_audio_size + sizeof(int64) * 2; + decoded_frames->SetFrameBuffer(host_->Allocate(buffer_size)); + if (!decoded_frames->FrameBuffer()) { + LOG(ERROR) << "DecodeBuffer() cdm::Host::Allocate failed."; + return cdm::kDecodeError; } + decoded_frames->FrameBuffer()->SetSize(buffer_size); + uint8_t* output_buffer = decoded_frames->FrameBuffer()->Data(); - output = new DataBuffer(decoded_audio_size); - output->set_data_size(decoded_audio_size); + const int64 timestamp = output_timestamp.InMicroseconds(); + memcpy(output_buffer, ×tamp, sizeof(timestamp)); + output_buffer += sizeof(timestamp); - DCHECK_EQ(frames_to_interleave, converter_bus_->frames() - skip_frames); - converter_bus_->ToInterleavedPartial( - skip_frames, frames_to_interleave, bits_per_channel_ / 8, - output->writable_data()); - } else { - output = DataBuffer::CopyFrom( - av_frame_->extended_data[0] + start_sample * bytes_per_frame_, - decoded_audio_size); - } + const int64 output_size = decoded_audio_size; + memcpy(output_buffer, &output_size, sizeof(output_size)); + output_buffer += sizeof(output_size); - base::TimeDelta output_timestamp = - output_timestamp_helper_->GetTimestamp(); - output_timestamp_helper_->AddFrames(decoded_audio_size / - bytes_per_frame_); + // Copy the samples and return success. + CopySamples( + cdm_format, decoded_audio_size, *av_frame_, output_buffer); + return cdm::kSuccess; + } - // Serialize the audio samples into |serialized_audio_frames_|. + // There are still more frames to decode, so we need to serialize them in + // a secondary buffer since we don't know their sizes ahead of time (which + // is required to allocate the FrameBuffer object). SerializeInt64(output_timestamp.InMicroseconds()); - SerializeInt64(output->data_size()); - serialized_audio_frames_.insert( - serialized_audio_frames_.end(), - output->data(), - output->data() + output->data_size()); + SerializeInt64(decoded_audio_size); + + const size_t previous_size = serialized_audio_frames_.size(); + serialized_audio_frames_.resize(previous_size + decoded_audio_size); + uint8_t* output_buffer = &serialized_audio_frames_[0] + previous_size; + CopySamples( + cdm_format, decoded_audio_size, *av_frame_, output_buffer); } } while (packet.size > 0); @@ -395,7 +421,7 @@ void FFmpegCdmAudioDecoder::ReleaseFFmpegResources() { } void FFmpegCdmAudioDecoder::SerializeInt64(int64 value) { - int previous_size = serialized_audio_frames_.size(); + const size_t previous_size = serialized_audio_frames_.size(); serialized_audio_frames_.resize(previous_size + sizeof(value)); memcpy(&serialized_audio_frames_[0] + previous_size, &value, sizeof(value)); } diff --git a/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.h b/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.h index 35a01df4bc016b..6e170ad4a82add 100644 --- a/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.h +++ b/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.h @@ -49,7 +49,7 @@ class FFmpegCdmAudioDecoder { cdm::Status DecodeBuffer(const uint8_t* compressed_buffer, int32_t compressed_buffer_size, int64_t timestamp, - cdm::AudioFrames_1* decoded_frames); + cdm::AudioFrames* decoded_frames); private: void ResetTimestampState(); @@ -68,7 +68,6 @@ class FFmpegCdmAudioDecoder { scoped_ptr_malloc av_frame_; // Audio format. - int bits_per_channel_; int samples_per_second_; int channels_; @@ -80,10 +79,6 @@ class FFmpegCdmAudioDecoder { int bytes_per_frame_; base::TimeDelta last_input_timestamp_; - // We may need to convert the audio data coming out of FFmpeg from planar - // float to integer. - scoped_ptr converter_bus_; - // Number of output sample bytes to drop before generating output buffers. // This is required for handling negative timestamps when decoding Vorbis // audio, for example. diff --git a/ppapi/api/private/pp_content_decryptor.idl b/ppapi/api/private/pp_content_decryptor.idl index aba404f8bb4144..41a399740838b2 100644 --- a/ppapi/api/private/pp_content_decryptor.idl +++ b/ppapi/api/private/pp_content_decryptor.idl @@ -139,6 +139,20 @@ enum PP_DecryptedFrameFormat { PP_DECRYPTEDFRAMEFORMAT_I420 = 2 }; +/** + * PP_DecryptedSampleFormat contains audio sample formats. + */ +[assert_size(4)] +enum PP_DecryptedSampleFormat { + PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN = 0, + PP_DECRYPTEDSAMPLEFORMAT_U8 = 1, + PP_DECRYPTEDSAMPLEFORMAT_S16 = 2, + PP_DECRYPTEDSAMPLEFORMAT_S32 = 3, + PP_DECRYPTEDSAMPLEFORMAT_F32 = 4, + PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16 = 5, + PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32 = 6 +}; + /** * The PP_DecryptResult enum contains decryption and decoding * result constants. @@ -234,6 +248,40 @@ struct PP_DecryptedFrameInfo { PP_DecryptTrackingInfo tracking_info; }; +/** + * PP_DecryptedSampleInfo contains the result of the + * decrypt and decode operation on the associated samples, information required + * to access the sample data in buffer, and tracking info. + */ +[assert_size(32)] +struct PP_DecryptedSampleInfo { + /** + * Result of the decrypt and decode operation. + */ + PP_DecryptResult result; + + /** + * Format of the decrypted samples. + */ + PP_DecryptedSampleFormat format; + + /** + * Size in bytes of decrypted samples. + */ + uint32_t data_size; + + /** + * 4-byte padding to make the size of PP_DecryptedSampleInfo + * a multiple of 8 bytes. The value of this field should not be used. + */ + uint32_t padding; + + /** + * Information needed by the client to track the decrypted samples. + */ + PP_DecryptTrackingInfo tracking_info; +}; + /** * PP_AudioCodec contains audio codec type constants. */ diff --git a/ppapi/api/private/ppb_content_decryptor_private.idl b/ppapi/api/private/ppb_content_decryptor_private.idl index 8859448d689651..fbf46636e96b63 100644 --- a/ppapi/api/private/ppb_content_decryptor_private.idl +++ b/ppapi/api/private/ppb_content_decryptor_private.idl @@ -12,7 +12,8 @@ [generate_thunk] label Chrome { - M31 = 0.7 + M31 = 0.7, + M32 = 0.8 }; /** @@ -228,12 +229,12 @@ interface PPB_ContentDecryptor_Private { * PPB_Buffer_Dev resource that contains a decrypted buffer * of decoded audio samples. * - * @param[in] decrypted_block_info A PP_DecryptedBlockInfo that - * contains the tracking info and result code associated with the - * decrypted_block. + * @param[in] decrypted_sample_info A PP_DecryptedSampleInfo that + * contains the tracking info and result code associated with the decrypted + * samples. */ void DeliverSamples( [in] PP_Instance instance, [in] PP_Resource audio_frames, - [in] PP_DecryptedBlockInfo decrypted_block_info); + [in] PP_DecryptedSampleInfo decrypted_sample_info); }; diff --git a/ppapi/c/private/pp_content_decryptor.h b/ppapi/c/private/pp_content_decryptor.h index 43ea559f128f64..a282abbf3a58c1 100644 --- a/ppapi/c/private/pp_content_decryptor.h +++ b/ppapi/c/private/pp_content_decryptor.h @@ -3,7 +3,7 @@ * found in the LICENSE file. */ -/* From private/pp_content_decryptor.idl modified Tue Dec 4 16:42:46 2012. */ +/* From private/pp_content_decryptor.idl modified Mon Oct 21 18:38:44 2013. */ #ifndef PPAPI_C_PRIVATE_PP_CONTENT_DECRYPTOR_H_ #define PPAPI_C_PRIVATE_PP_CONTENT_DECRYPTOR_H_ @@ -152,6 +152,20 @@ typedef enum { } PP_DecryptedFrameFormat; PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_DecryptedFrameFormat, 4); +/** + * PP_DecryptedSampleFormat contains audio sample formats. + */ +typedef enum { + PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN = 0, + PP_DECRYPTEDSAMPLEFORMAT_U8 = 1, + PP_DECRYPTEDSAMPLEFORMAT_S16 = 2, + PP_DECRYPTEDSAMPLEFORMAT_S32 = 3, + PP_DECRYPTEDSAMPLEFORMAT_F32 = 4, + PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16 = 5, + PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32 = 6 +} PP_DecryptedSampleFormat; +PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_DecryptedSampleFormat, 4); + /** * The PP_DecryptResult enum contains decryption and decoding * result constants. @@ -259,6 +273,36 @@ struct PP_DecryptedFrameInfo { struct PP_DecryptTrackingInfo tracking_info; }; PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(PP_DecryptedFrameInfo, 56); + +/** + * PP_DecryptedSampleInfo contains the result of the + * decrypt and decode operation on the associated samples, information required + * to access the sample data in buffer, and tracking info. + */ +struct PP_DecryptedSampleInfo { + /** + * Result of the decrypt and decode operation. + */ + PP_DecryptResult result; + /** + * Format of the decrypted samples. + */ + PP_DecryptedSampleFormat format; + /** + * Size in bytes of decrypted samples. + */ + uint32_t data_size; + /** + * 4-byte padding to make the size of PP_DecryptedSampleInfo + * a multiple of 8 bytes. The value of this field should not be used. + */ + uint32_t padding; + /** + * Information needed by the client to track the decrypted samples. + */ + struct PP_DecryptTrackingInfo tracking_info; +}; +PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(PP_DecryptedSampleInfo, 32); /** * @} */ diff --git a/ppapi/c/private/ppb_content_decryptor_private.h b/ppapi/c/private/ppb_content_decryptor_private.h index 86f239aab10a94..5e3d1aa4df2d13 100644 --- a/ppapi/c/private/ppb_content_decryptor_private.h +++ b/ppapi/c/private/ppb_content_decryptor_private.h @@ -4,7 +4,7 @@ */ /* From private/ppb_content_decryptor_private.idl, - * modified Tue Sep 17 11:31:05 2013. + * modified Thu Oct 10 14:49:51 2013. */ #ifndef PPAPI_C_PRIVATE_PPB_CONTENT_DECRYPTOR_PRIVATE_H_ @@ -234,14 +234,14 @@ struct PPB_ContentDecryptor_Private_0_7 { * PPB_Buffer_Dev resource that contains a decrypted buffer * of decoded audio samples. * - * @param[in] decrypted_block_info A PP_DecryptedBlockInfo that - * contains the tracking info and result code associated with the - * decrypted_block. + * @param[in] decrypted_sample_info A PP_DecryptedSampleInfo that + * contains the tracking info and result code associated with the decrypted + * samples. */ void (*DeliverSamples)( PP_Instance instance, PP_Resource audio_frames, - const struct PP_DecryptedBlockInfo* decrypted_block_info); + const struct PP_DecryptedSampleInfo* decrypted_sample_info); }; typedef struct PPB_ContentDecryptor_Private_0_7 PPB_ContentDecryptor_Private; diff --git a/ppapi/cpp/private/content_decryptor_private.cc b/ppapi/cpp/private/content_decryptor_private.cc index 23417c3e155b62..8c7dcd285094f5 100644 --- a/ppapi/cpp/private/content_decryptor_private.cc +++ b/ppapi/cpp/private/content_decryptor_private.cc @@ -330,12 +330,12 @@ void ContentDecryptor_Private::DeliverFrame( void ContentDecryptor_Private::DeliverSamples( pp::Buffer_Dev audio_frames, - const PP_DecryptedBlockInfo& decrypted_block_info) { + const PP_DecryptedSampleInfo& decrypted_sample_info) { if (has_interface()) { get_interface()->DeliverSamples( associated_instance_.pp_instance(), audio_frames.pp_resource(), - &decrypted_block_info); + &decrypted_sample_info); } } diff --git a/ppapi/cpp/private/content_decryptor_private.h b/ppapi/cpp/private/content_decryptor_private.h index a43a74cfb83f6d..ff985691e11233 100644 --- a/ppapi/cpp/private/content_decryptor_private.h +++ b/ppapi/cpp/private/content_decryptor_private.h @@ -94,7 +94,7 @@ class ContentDecryptor_Private { // provided to DecryptAndDecode() when it calls this method. The browser will // reuse the buffer in a subsequent DecryptAndDecode() call. void DeliverSamples(pp::Buffer_Dev audio_frames, - const PP_DecryptedBlockInfo& decrypted_block_info); + const PP_DecryptedSampleInfo& decrypted_sample_info); private: InstanceHandle associated_instance_; diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c index 9e3b477f65eb9b..09065175add810 100644 --- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c +++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c @@ -2523,9 +2523,9 @@ static void Pnacl_M31_PPB_ContentDecryptor_Private_DeliverFrame(PP_Instance inst iface->DeliverFrame(instance, decrypted_frame, decrypted_frame_info); } -static void Pnacl_M31_PPB_ContentDecryptor_Private_DeliverSamples(PP_Instance instance, PP_Resource audio_frames, const struct PP_DecryptedBlockInfo* decrypted_block_info) { +static void Pnacl_M31_PPB_ContentDecryptor_Private_DeliverSamples(PP_Instance instance, PP_Resource audio_frames, const struct PP_DecryptedSampleInfo* decrypted_sample_info) { const struct PPB_ContentDecryptor_Private_0_7 *iface = Pnacl_WrapperInfo_PPB_ContentDecryptor_Private_0_7.real_iface; - iface->DeliverSamples(instance, audio_frames, decrypted_block_info); + iface->DeliverSamples(instance, audio_frames, decrypted_sample_info); } /* End wrapper methods for PPB_ContentDecryptor_Private_0_7 */ @@ -4800,7 +4800,7 @@ struct PPB_ContentDecryptor_Private_0_7 Pnacl_Wrappers_PPB_ContentDecryptor_Priv .DecoderDeinitializeDone = (void (*)(PP_Instance instance, PP_DecryptorStreamType decoder_type, uint32_t request_id))&Pnacl_M31_PPB_ContentDecryptor_Private_DecoderDeinitializeDone, .DecoderResetDone = (void (*)(PP_Instance instance, PP_DecryptorStreamType decoder_type, uint32_t request_id))&Pnacl_M31_PPB_ContentDecryptor_Private_DecoderResetDone, .DeliverFrame = (void (*)(PP_Instance instance, PP_Resource decrypted_frame, const struct PP_DecryptedFrameInfo* decrypted_frame_info))&Pnacl_M31_PPB_ContentDecryptor_Private_DeliverFrame, - .DeliverSamples = (void (*)(PP_Instance instance, PP_Resource audio_frames, const struct PP_DecryptedBlockInfo* decrypted_block_info))&Pnacl_M31_PPB_ContentDecryptor_Private_DeliverSamples + .DeliverSamples = (void (*)(PP_Instance instance, PP_Resource audio_frames, const struct PP_DecryptedSampleInfo* decrypted_sample_info))&Pnacl_M31_PPB_ContentDecryptor_Private_DeliverSamples }; struct PPB_Ext_CrxFileSystem_Private_0_1 Pnacl_Wrappers_PPB_Ext_CrxFileSystem_Private_0_1 = { diff --git a/ppapi/proxy/ppb_instance_proxy.cc b/ppapi/proxy/ppb_instance_proxy.cc index fdaa8c47d2546f..1997f8900826cf 100644 --- a/ppapi/proxy/ppb_instance_proxy.cc +++ b/ppapi/proxy/ppb_instance_proxy.cc @@ -675,7 +675,7 @@ void PPB_Instance_Proxy::DeliverFrame(PP_Instance instance, void PPB_Instance_Proxy::DeliverSamples( PP_Instance instance, PP_Resource decrypted_samples, - const PP_DecryptedBlockInfo* block_info) { + const PP_DecryptedSampleInfo* sample_info) { PP_Resource host_resource = 0; if (decrypted_samples != 0) { ResourceTracker* tracker = PpapiGlobals::Get()->GetResourceTracker(); @@ -689,8 +689,8 @@ void PPB_Instance_Proxy::DeliverSamples( host_resource = object->host_resource().host_resource(); } - std::string serialized_block_info; - if (!SerializeBlockInfo(*block_info, &serialized_block_info)) { + std::string serialized_sample_info; + if (!SerializeBlockInfo(*sample_info, &serialized_sample_info)) { NOTREACHED(); return; } @@ -699,7 +699,7 @@ void PPB_Instance_Proxy::DeliverSamples( new PpapiHostMsg_PPBInstance_DeliverSamples(API_ID_PPB_INSTANCE, instance, host_resource, - serialized_block_info)); + serialized_sample_info)); } #endif // !defined(OS_NACL) @@ -1165,16 +1165,16 @@ void PPB_Instance_Proxy::OnHostMsgDeliverFrame( void PPB_Instance_Proxy::OnHostMsgDeliverSamples( PP_Instance instance, PP_Resource audio_frames, - const std::string& serialized_block_info) { + const std::string& serialized_sample_info) { if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) return; - PP_DecryptedBlockInfo block_info; - if (!DeserializeBlockInfo(serialized_block_info, &block_info)) + PP_DecryptedSampleInfo sample_info; + if (!DeserializeBlockInfo(serialized_sample_info, &sample_info)) return; EnterInstanceNoLock enter(instance); if (enter.succeeded()) - enter.functions()->DeliverSamples(instance, audio_frames, &block_info); + enter.functions()->DeliverSamples(instance, audio_frames, &sample_info); } void PPB_Instance_Proxy::OnHostMsgSetCursor( diff --git a/ppapi/proxy/ppb_instance_proxy.h b/ppapi/proxy/ppb_instance_proxy.h index a6516bc1754f92..5aaa2d11a631f0 100644 --- a/ppapi/proxy/ppb_instance_proxy.h +++ b/ppapi/proxy/ppb_instance_proxy.h @@ -146,9 +146,10 @@ class PPB_Instance_Proxy : public InterfaceProxy, 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; #endif // !defined(OS_NACL) static const ApiID kApiID = API_ID_PPB_INSTANCE; @@ -253,7 +254,7 @@ class PPB_Instance_Proxy : public InterfaceProxy, virtual void OnHostMsgDeliverSamples( PP_Instance instance, PP_Resource audio_frames, - const std::string& serialized_block_info); + const std::string& serialized_sample_info); #endif // !defined(OS_NACL) // Host -> Plugin message handlers. diff --git a/ppapi/thunk/ppb_content_decryptor_private_thunk.cc b/ppapi/thunk/ppb_content_decryptor_private_thunk.cc index 7fe79e12848a1b..a43d24dea6bf50 100644 --- a/ppapi/thunk/ppb_content_decryptor_private_thunk.cc +++ b/ppapi/thunk/ppb_content_decryptor_private_thunk.cc @@ -3,7 +3,7 @@ // found in the LICENSE file. // From private/ppb_content_decryptor_private.idl, -// modified Tue Sep 17 11:31:05 2013. +// modified Thu Oct 10 14:49:51 2013. #include "ppapi/c/pp_errors.h" #include "ppapi/c/private/ppb_content_decryptor_private.h" @@ -123,14 +123,14 @@ void DeliverFrame(PP_Instance instance, void DeliverSamples( PP_Instance instance, PP_Resource audio_frames, - const struct PP_DecryptedBlockInfo* decrypted_block_info) { + const struct PP_DecryptedSampleInfo* decrypted_sample_info) { VLOG(4) << "PPB_ContentDecryptor_Private::DeliverSamples()"; EnterInstance enter(instance); if (enter.failed()) return; enter.functions()->DeliverSamples(instance, audio_frames, - decrypted_block_info); + decrypted_sample_info); } const PPB_ContentDecryptor_Private_0_7 diff --git a/ppapi/thunk/ppb_instance_api.h b/ppapi/thunk/ppb_instance_api.h index 0d424a5ed535f9..93eba9ca4f23b5 100644 --- a/ppapi/thunk/ppb_instance_api.h +++ b/ppapi/thunk/ppb_instance_api.h @@ -173,7 +173,7 @@ class PPB_Instance_API { const PP_DecryptedFrameInfo* frame_info) = 0; virtual void DeliverSamples(PP_Instance instance, PP_Resource audio_frames, - const PP_DecryptedBlockInfo* block_info) = 0; + const PP_DecryptedSampleInfo* sample_info) = 0; // URLUtil. virtual PP_Var ResolveRelativeToDocument(