blob: b53ac777343c9dcce09a9a73e4c9f7825cea1292 [file] [log] [blame]
/*
* 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