* Copyright (C) 2023 Huawei Device Co., Ltd.
* 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.
*/
#include "av_surface_memory.h"
#include <unistd.h>
#include "av_surface_allocator.h"
#include "common/log.h"
#include "common/status.h"
#include "message_parcel.h"
#include "scope_guard.h"
#include "surface_buffer.h"
#include "surface_type.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "AVSurfaceMemory" };
}
namespace OHOS {
namespace Media {
std::shared_ptr<AVAllocator> AVAllocatorFactory::CreateSurfaceAllocator(const BufferRequestConfig &config)
{
auto allocator = std::shared_ptr<AVSurfaceAllocator>(new AVSurfaceAllocator());
FALSE_RETURN_V_MSG_E(allocator != nullptr, nullptr, "Create AVSurfaceAllocator failed, no memory");
allocator->config_ = config;
return allocator;
}
AVSurfaceAllocator::AVSurfaceAllocator()
{
config_ = {
.width = 0,
.height = 0,
.strideAlignment = 0x0,
.format = GraphicPixelFormat::GRAPHIC_PIXEL_FMT_RGBA_8888,
.usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
.timeout = 0,
};
}
void *AVSurfaceAllocator::Alloc(int32_t capacity)
{
(void)capacity;
sptr<SurfaceBuffer> surfaceBuffer = SurfaceBuffer::Create();
FALSE_RETURN_V_MSG_E(surfaceBuffer != nullptr, nullptr, "No memory for new SurfaceBuffer!");
GSError ret = surfaceBuffer->Alloc(config_);
FALSE_RETURN_V_MSG_E(ret == GSERROR_OK, nullptr, "Surface Buffer Alloc failed, %{public}s",
GSErrorStr(ret).c_str());
surfaceBuffer->IncStrongRef(surfaceBuffer.GetRefPtr());
return static_cast<void *>(surfaceBuffer.GetRefPtr());
}
bool AVSurfaceAllocator::Free(void *ptr)
{
FALSE_RETURN_V_MSG_E(ptr != nullptr, false, "ptr is nullptr");
sptr<SurfaceBuffer> surfaceBuffer = sptr<SurfaceBuffer>(static_cast<SurfaceBuffer *>(ptr));
surfaceBuffer->DecStrongRef(surfaceBuffer.GetRefPtr());
MEDIA_LOG_DD("GetSptrRefCount:%{public}d", surfaceBuffer->GetSptrRefCount());
surfaceBuffer = nullptr;
return true;
}
MemoryType AVSurfaceAllocator::GetMemoryType()
{
return MemoryType::SURFACE_MEMORY;
}
AVSurfaceMemory::AVSurfaceMemory() : isFirstFlag_(true) {}
AVSurfaceMemory::~AVSurfaceMemory()
{
if (base_ != nullptr) {
base_ = nullptr;
}
if (allocator_ != nullptr) {
bool ret = allocator_->Free(surfaceBuffer_.GetRefPtr());
FALSE_RETURN_MSG(ret, "Free memory failed, instance: 0x%{public}06" PRIXPTR, FAKE_POINTER(this));
}
surfaceBuffer_ = nullptr;
}
Status AVSurfaceMemory::Init()
{
surfaceBuffer_ = sptr<SurfaceBuffer>(static_cast<SurfaceBuffer *>(allocator_->Alloc(0)));
FALSE_RETURN_V_MSG_E(surfaceBuffer_ != nullptr, Status::ERROR_NO_MEMORY, "surfaceBuffer_ alloc failed");
capacity_ = static_cast<int32_t>(surfaceBuffer_->GetSize());
return Status::OK;
}
Status AVSurfaceMemory::Init(MessageParcel &parcel)
{
return InitSurfaceBuffer(parcel);
}
Status AVSurfaceMemory::InitSurfaceBuffer(MessageParcel &parcel)
{
if (!parcel.ReadBool()) {
return Status::ERROR_INVALID_DATA;
}
surfaceBuffer_ = SurfaceBuffer::Create();
FALSE_RETURN_V_MSG_E(surfaceBuffer_ != nullptr, Status::ERROR_NO_MEMORY, "No memory for new SurfaceBuffer!");
GSError ret = surfaceBuffer_->ReadFromMessageParcel(parcel);
FALSE_RETURN_V_MSG_E(ret == GSERROR_OK, Status::ERROR_INVALID_OPERATION, "Read message parcel failed! %{public}s",
GSErrorStr(ret).c_str());
capacity_ = static_cast<int32_t>(surfaceBuffer_->GetSize());
return Status::OK;
}
Status AVSurfaceMemory::InitSurfaceBuffer(sptr<SurfaceBuffer> surfaceBuffer)
{
surfaceBuffer_ = surfaceBuffer;
capacity_ = static_cast<int32_t>(surfaceBuffer_->GetSize());
size_ = capacity_;
return Status::OK;
}
bool AVSurfaceMemory::WriteToMessageParcel(MessageParcel &parcel, bool updateAVMemory)
{
#ifdef MEDIA_OHOS
auto oldPos = parcel.GetWritePosition();
auto oldSize = parcel.GetDataSize();
bool ret = parcel.WriteBool(updateAVMemory);
if (ret && updateAVMemory) {
GSError ret = surfaceBuffer_->WriteToMessageParcel(parcel);
FALSE_RETURN_V_MSG_E(ret == GSERROR_OK, false, "Write message parcel failed!, %{public}s",
GSErrorStr(ret).c_str());
}
if (!ret) {
parcel.RewindWrite(oldPos);
parcel.SetDataSize(oldSize);
}
return ret;
#else
return true;
#endif
}
bool AVSurfaceMemory::ReadFromMessageParcel(MessageParcel &parcel)
{
#ifdef MEDIA_OHOS
if (!parcel.ReadBool()) {
return true;
}
GSError ret = surfaceBuffer_->ReadFromMessageParcel(parcel);
FALSE_RETURN_V_MSG_E(ret == GSERROR_OK, false, "Read message parcel failed!, %{public}s",
GSErrorStr(ret).c_str());
#endif
return true;
}
uint8_t *AVSurfaceMemory::GetAddr()
{
if (isFirstFlag_) {
base_ = reinterpret_cast<uint8_t *>(surfaceBuffer_->GetVirAddr());
isFirstFlag_ = false;
}
return base_;
}
MemoryType AVSurfaceMemory::GetMemoryType()
{
return MemoryType::SURFACE_MEMORY;
}
int32_t AVSurfaceMemory::GetFileDescriptor()
{
return surfaceBuffer_->GetFileDescriptor();
}
sptr<SurfaceBuffer> AVSurfaceMemory::GetSurfaceBuffer()
{
return surfaceBuffer_;
}
}
}