| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| //#define LOG_NDEBUG 0 |
| #define LOG_TAG "DataConverter" |
| |
| #include "include/DataConverter.h" |
| |
| #include <audio_utils/primitives.h> |
| |
| #include <media/MediaCodecBuffer.h> |
| #include <media/stagefright/foundation/ADebug.h> |
| #include <media/stagefright/foundation/AUtils.h> |
| #include <system/audio.h> |
| #include <audio_utils/primitives.h> |
| #include <audio_utils/format.h> |
| |
| |
| namespace android { |
| |
| status_t DataConverter::convert(const sp<MediaCodecBuffer> &source, sp<MediaCodecBuffer> &target) { |
| CHECK(source->base() != target->base()); |
| size_t size = targetSize(source->size()); |
| status_t err = OK; |
| if (size > target->capacity()) { |
| ALOGE("data size (%zu) is greater than buffer capacity (%zu)", |
| size, // this is the data received/to be converted |
| target->capacity()); // this is out buffer size |
| err = FAILED_TRANSACTION; |
| } else { |
| err = safeConvert(source, target); |
| } |
| target->setRange(0, err == OK ? size : 0); |
| return err; |
| } |
| |
| status_t DataConverter::safeConvert( |
| const sp<MediaCodecBuffer> &source, sp<MediaCodecBuffer> &target) { |
| memcpy(target->base(), source->data(), source->size()); |
| return OK; |
| } |
| |
| size_t DataConverter::sourceSize(size_t targetSize) { |
| return targetSize; |
| } |
| |
| size_t DataConverter::targetSize(size_t sourceSize) { |
| return sourceSize; |
| } |
| |
| DataConverter::~DataConverter() { } |
| |
| |
| size_t SampleConverterBase::sourceSize(size_t targetSize) { |
| size_t numSamples = targetSize / mTargetSampleSize; |
| if (numSamples > SIZE_MAX / mSourceSampleSize) { |
| ALOGW("limiting source size due to overflow (%zu*%zu/%zu)", |
| targetSize, mSourceSampleSize, mTargetSampleSize); |
| return SIZE_MAX; |
| } |
| return numSamples * mSourceSampleSize; |
| } |
| |
| size_t SampleConverterBase::targetSize(size_t sourceSize) { |
| // we round up on conversion |
| size_t numSamples = divUp(sourceSize, (size_t)mSourceSampleSize); |
| if (numSamples > SIZE_MAX / mTargetSampleSize) { |
| ALOGW("limiting target size due to overflow (%zu*%zu/%zu)", |
| sourceSize, mTargetSampleSize, mSourceSampleSize); |
| return SIZE_MAX; |
| } |
| return numSamples * mTargetSampleSize; |
| } |
| |
| static audio_format_t getAudioFormat(AudioEncoding e) { |
| audio_format_t format = AUDIO_FORMAT_INVALID; |
| switch (e) { |
| case kAudioEncodingPcm16bit: |
| format = AUDIO_FORMAT_PCM_16_BIT; |
| break; |
| case kAudioEncodingPcm8bit: |
| format = AUDIO_FORMAT_PCM_8_BIT; |
| break; |
| case kAudioEncodingPcmFloat: |
| format = AUDIO_FORMAT_PCM_FLOAT; |
| break; |
| case kAudioEncodingPcm24bitPacked: |
| format = AUDIO_FORMAT_PCM_24_BIT_PACKED; |
| break; |
| case kAudioEncodingPcm32bit: |
| format = AUDIO_FORMAT_PCM_32_BIT; |
| break; |
| default: |
| ALOGE("Invalid AudioEncoding %d", e); |
| } |
| return format; |
| } |
| |
| static size_t getAudioSampleSize(AudioEncoding e) { |
| switch (e) { |
| case kAudioEncodingPcm16bit: |
| case kAudioEncodingPcm8bit: |
| case kAudioEncodingPcmFloat: |
| case kAudioEncodingPcm24bitPacked: |
| case kAudioEncodingPcm32bit: |
| return audio_bytes_per_sample(getAudioFormat(e)); |
| default: return 0; |
| } |
| } |
| |
| |
| // static |
| AudioConverter* AudioConverter::Create(AudioEncoding source, AudioEncoding target) { |
| uint32_t sourceSampleSize = getAudioSampleSize(source); |
| uint32_t targetSampleSize = getAudioSampleSize(target); |
| if (sourceSampleSize && targetSampleSize && sourceSampleSize != targetSampleSize) { |
| return new AudioConverter(source, sourceSampleSize, target, targetSampleSize); |
| } |
| return NULL; |
| } |
| |
| status_t AudioConverter::safeConvert(const sp<MediaCodecBuffer> &src, sp<MediaCodecBuffer> &tgt) { |
| if (mTo == kAudioEncodingPcm8bit && mFrom == kAudioEncodingPcm16bit) { |
| memcpy_to_u8_from_i16((uint8_t*)tgt->base(), (const int16_t*)src->data(), src->size() / 2); |
| } else if (mTo == kAudioEncodingPcm8bit && mFrom == kAudioEncodingPcmFloat) { |
| memcpy_to_u8_from_float((uint8_t*)tgt->base(), (const float*)src->data(), src->size() / 4); |
| } else if (mTo == kAudioEncodingPcm16bit && mFrom == kAudioEncodingPcm8bit) { |
| memcpy_to_i16_from_u8((int16_t*)tgt->base(), (const uint8_t*)src->data(), src->size()); |
| } else if (mTo == kAudioEncodingPcm16bit && mFrom == kAudioEncodingPcmFloat) { |
| memcpy_to_i16_from_float((int16_t*)tgt->base(), (const float*)src->data(), src->size() / 4); |
| } else if (mTo == kAudioEncodingPcmFloat && mFrom == kAudioEncodingPcm8bit) { |
| memcpy_to_float_from_u8((float*)tgt->base(), (const uint8_t*)src->data(), src->size()); |
| } else if (mTo == kAudioEncodingPcmFloat && mFrom == kAudioEncodingPcm16bit) { |
| memcpy_to_float_from_i16((float*)tgt->base(), (const int16_t*)src->data(), src->size() / 2); |
| } else { |
| audio_format_t srcFormat = getAudioFormat(mFrom); |
| audio_format_t dstFormat = getAudioFormat(mTo); |
| |
| if ((srcFormat == AUDIO_FORMAT_INVALID) || (dstFormat == AUDIO_FORMAT_INVALID)) |
| return INVALID_OPERATION; |
| |
| size_t frames = src->size() / audio_bytes_per_sample(srcFormat); |
| memcpy_by_audio_format((void*)tgt->base(), dstFormat, (void*)src->data(), |
| srcFormat, frames); |
| } |
| return OK; |
| } |
| |
| } // namespace android |