!49 封装Muxer合入

Merge pull request !49 from cailei24/dev_av_muxer
This commit is contained in:
cailei24 2023-04-26 08:30:29 +00:00 committed by Gitee
commit aed543404e
93 changed files with 5855 additions and 963 deletions

View File

@ -17,6 +17,6 @@ import("//build/ohos.gni")
group("av_codec_packages") {
public_deps = [
"interfaces/inner_api/native:av_codec_client",
"services:av_codec_service",
"services/services:av_codec_service",
]
}

View File

@ -77,9 +77,10 @@
}
}
],
"test": [
"//foundation/multimedia/av_codec/test:av_codec_demo_test"
]
"test": [
"//foundation/multimedia/av_codec/test:av_codec_demo_test",
"//foundation/multimedia/av_codec/test:av_codec_unit_test"
]
}
}
}

View File

@ -13,12 +13,12 @@
declare_args() {
multimedia_av_codec_support_capi = true
multimedia_av_codec_support_codec = true
multimedia_av_codec_support_codec = false
multimedia_av_codec_support_codeclist = false
multimedia_av_codec_support_demuxer = false
multimedia_av_codec_support_muxer = true
multimedia_av_codec_support_ffmpeg_demuxer = false
multimedia_av_codec_support_test = false
multimedia_av_codec_support_test = true
}
av_codec_defines = []

View File

@ -14,15 +14,14 @@
*/
#include "avmuxer_impl.h"
#include <fcntl.h>
#include <unistd.h>
#include <functional>
#include <sys/types.h>
#include <fcntl.h>
#include "securec.h"
#include "i_avcodec_service.h"
#include "avcodec_log.h"
#include "avsharedmemorybase.h"
#include "avcodec_dfx.h"
#include "i_avcodec_service.h"
#include "avcodec_errors.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMuxerImpl"};
@ -30,9 +29,9 @@ namespace {
namespace OHOS {
namespace Media {
std::shared_ptr<AVMuxer> AVMuxerFactory::CreateAVMuxer(int32_t fd, AVOutputFormat format)
std::shared_ptr<AVMuxer> AVMuxerFactory::CreateAVMuxer(int32_t fd, OutputFormat format)
{
AVCodecTrace trace(std::string(__FUNCTION__));
AVCodecTrace trace("AVMuxerFactory::CreateAVMuxer");
CHECK_AND_RETURN_RET_LOG((fcntl(fd, F_GETFL, 0) & O_RDWR) == O_RDWR, nullptr, "No permission to read and write fd");
CHECK_AND_RETURN_RET_LOG(lseek(fd, 0, SEEK_CUR) != -1, nullptr, "The fd is not seekable");
@ -44,7 +43,7 @@ std::shared_ptr<AVMuxer> AVMuxerFactory::CreateAVMuxer(int32_t fd, AVOutputForma
return impl;
}
AVMuxerImpl::AVMuxerImpl(int32_t fd, AVOutputFormat format) : fd_(fd), format_(format)
AVMuxerImpl::AVMuxerImpl(int32_t fd, OutputFormat format) : fd_(fd), format_(format)
{
(void)fd_;
(void)format_;
@ -53,77 +52,77 @@ AVMuxerImpl::AVMuxerImpl(int32_t fd, AVOutputFormat format) : fd_(fd), format_(f
AVMuxerImpl::~AVMuxerImpl()
{
if (muxerClient_ != nullptr) {
(void)AVCodecServiceFactory::GetInstance().DestroyMuxerService(muxerClient_);
muxerClient_ = nullptr;
if (muxerService_ != nullptr) {
(void)muxerService_->Release();
(void)AVCodecServiceFactory::GetInstance().DestroyMuxerService(muxerService_);
muxerService_ = nullptr;
}
AVCODEC_LOGD("AVMuxerImpl:0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
}
int32_t AVMuxerImpl::Init()
{
AVCodecTrace trace(std::string(__FUNCTION__));
muxerClient_ = AVCodecServiceFactory::GetInstance().CreateMuxerService();
CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Create avmuxer engine failed");
return AVCS_ERR_OK;
AVCodecTrace trace("AVMuxer::Init");
AVCODEC_LOGI("Init");
muxerService_ = AVCodecServiceFactory::GetInstance().CreateMuxerService();
CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_NO_MEMORY, "Create AVMuxer Service failed");
return muxerService_->InitParameter(fd_, format_);
}
int32_t AVMuxerImpl::SetLocation(float latitude, float longitude)
{
AVCodecTrace trace(std::string(__FUNCTION__));
CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist");
return muxerClient_->SetLocation(latitude, longitude);
AVCodecTrace trace("AVMuxer::SetLocation");
AVCODEC_LOGI("SetLocation");
CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Service does not exist");
return muxerService_->SetLocation(latitude, longitude);
}
int32_t AVMuxerImpl::SetRotation(int32_t rotation)
{
AVCodecTrace trace(std::string(__FUNCTION__));
CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist");
return muxerClient_->SetRotation(rotation);
AVCodecTrace trace("AVMuxer::SetRotation");
AVCODEC_LOGI("SetRotation");
CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Service does not exist");
return muxerService_->SetRotation(rotation);
}
int32_t AVMuxerImpl::SetParameter(const Format &generalFormat)
int32_t AVMuxerImpl::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc)
{
AVCodecTrace trace(std::string(__FUNCTION__));
CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist");
return muxerClient_->SetParameter(generalFormat);
}
int32_t AVMuxerImpl::AddTrack(uint32_t &trackIndex, const Format &trackFormat)
{
AVCodecTrace trace(std::string(__FUNCTION__));
CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist");
return muxerClient_->AddTrack(trackIndex, trackFormat);
AVCodecTrace trace("AVMuxer::AddTrack");
AVCODEC_LOGI("AddTrack");
CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Service does not exist");
return muxerService_->AddTrack(trackIndex, trackDesc);
}
int32_t AVMuxerImpl::Start()
{
AVCodecTrace trace(std::string(__FUNCTION__));
CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist");
return muxerClient_->Start();
AVCodecTrace trace("AVMuxer::Start");
AVCODEC_LOGI("Start");
CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Service does not exist");
return muxerService_->Start();
}
int32_t AVMuxerImpl::WriteSampleBuffer(uint32_t trackIndex, uint8_t *sampleBuffer, AVCodecBufferInfo info)
int32_t AVMuxerImpl::WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info)
{
AVCodecTrace trace(std::string(__FUNCTION__));
CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist");
CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr && info.offset >= 0 && info.size >= 0,
AVCS_ERR_INVALID_VAL, "Invalid memory");
AVCodecTrace trace("AVMuxer::WriteSampleBuffer");
CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Service does not exist");
CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr && info.timeUs >= 0, AVCS_ERR_INVALID_VAL, "Invalid memory");
std::shared_ptr<AVSharedMemory> sharedSampleBuffer =
AVSharedMemoryBase::CreateFromLocal(info.size, AVSharedMemory::FLAGS_READ_ONLY, "SampleBuffer");
CHECK_AND_RETURN_RET_LOG(sharedSampleBuffer == nullptr, AVCS_ERR_NO_MEMORY, "Create AVSharedMemoryBase failed");
errno_t rc = memcpy_s(sharedSampleBuffer->GetBase(), sharedSampleBuffer->GetSize(), sampleBuffer + info.offset, info.size);
std::shared_ptr<AVSharedMemoryBase> sharedSampleBuffer =
std::make_shared<AVSharedMemoryBase>(info.size, AVSharedMemory::FLAGS_READ_ONLY, "sampleBuffer");
int32_t ret = sharedSampleBuffer->Init();
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_NO_MEMORY, "create AVSharedMemoryBase failed");
errno_t rc = memcpy_s(sharedSampleBuffer->GetBase(), sharedSampleBuffer->GetSize(), sampleBuffer, info.size);
CHECK_AND_RETURN_RET_LOG(rc == EOK, AVCS_ERR_UNKNOWN, "memcpy_s failed");
return muxerClient_->WriteSampleBuffer(trackIndex, sharedSampleBuffer, info);
return muxerService_->WriteSampleBuffer(sharedSampleBuffer, info);
}
int32_t AVMuxerImpl::Stop()
{
AVCodecTrace trace(std::string(__FUNCTION__));
CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist");
return muxerClient_->Stop();
AVCodecTrace trace("AVMuxer::Stop");
AVCODEC_LOGI("Stop");
CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Service does not exist");
return muxerService_->Stop();
}
} // namespace Media
} // namespace OHOS

View File

@ -16,28 +16,27 @@
#define AVMUXER_IMPL_H
#include "avmuxer.h"
#include "i_avmuxer.h"
#include "i_muxer_service.h"
#include "nocopyable.h"
namespace OHOS {
namespace Media {
class AVMuxerImpl : public AVMuxer, public NoCopyable {
public:
AVMuxerImpl(int32_t fd, AVOutputFormat format);
AVMuxerImpl(int32_t fd, OutputFormat format);
~AVMuxerImpl() override;
int32_t Init();
int32_t SetLocation(float latitude, float longitude) override;
int32_t SetRotation(int32_t rotation) override;
int32_t SetParameter(const Format &generalFormat) override;
int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) override;
int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override;
int32_t Start() override;
int32_t WriteSampleBuffer(uint32_t trackIndex, uint8_t *sampleBuffer, AVCodecBufferInfo info) override;
int32_t WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info) override;
int32_t Stop() override;
private:
std::shared_ptr<IAVMuxer> muxerClient_ = nullptr;
std::shared_ptr<IMuxerService> muxerService_ = nullptr;
int32_t fd_ = -1;
AVOutputFormat format_ = AV_OUTPUT_FORMAT_UNKNOWN;
OutputFormat format_ = OUTPUT_FORMAT_UNKNOWN;
};
} // namespace Media
} // namespace OHOS

View File

@ -20,7 +20,12 @@ extern "C" {
#endif
const char *OH_AVCODEC_MIMETYPE_VIDEO_AVC = "video/avc";
const char *OH_AVCODEC_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
const char *OH_AVCODEC_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
const char *OH_AVCODEC_MIMETYPE_AUDIO_MPEG = "audio/mpeg";
const char *OH_AVCODEC_MIMETYPE_IMAGE_JPG = "image/jpeg";
const char *OH_AVCODEC_MIMETYPE_IMAGE_PNG = "image/png";
const char *OH_AVCODEC_MIMETYPE_IMAGE_BMP = "image/bmp";
const char *OH_ED_KEY_TIME_STAMP = "timeStamp";
const char *OH_ED_KEY_EOS = "endOfStream";
const char *OH_MD_KEY_TRACK_TYPE = "track_type";
@ -39,6 +44,7 @@ const char *OH_MD_KEY_AUD_CHANNEL_COUNT = "channel_count";
const char *OH_MD_KEY_AUD_SAMPLE_RATE = "sample_rate";
const char *OH_MD_KEY_I_FRAME_INTERVAL = "i_frame_interval";
const char *OH_MD_KEY_ROTATION = "rotation_angle";
const char *OH_MD_KEY_CODEC_CONFIG = "codec_config";
#ifdef __cplusplus
}

View File

@ -17,6 +17,7 @@
#include "native_avmagic.h"
#include "avmuxer.h"
#include "avcodec_log.h"
#include "avcodec_errors.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "NativeAVMuxer"};
@ -34,7 +35,7 @@ struct AVMuxerObject : public OH_AVMuxer {
struct OH_AVMuxer *OH_AVMuxer_Create(int32_t fd, OH_AVOutputFormat format) {
CHECK_AND_RETURN_RET_LOG(fd >= 0, nullptr, "fd %{public}d is error!", fd);
std::shared_ptr<AVMuxer> avmuxer = AVMuxerFactory::CreateAVMuxer(fd, static_cast<AVOutputFormat>(format));
std::shared_ptr<AVMuxer> avmuxer = AVMuxerFactory::CreateAVMuxer(fd, static_cast<OutputFormat>(format));
CHECK_AND_RETURN_RET_LOG(avmuxer != nullptr, nullptr, "create muxer failed!");
struct AVMuxerObject *object = new(std::nothrow) AVMuxerObject(avmuxer);
return object;
@ -60,23 +61,18 @@ OH_AVErrCode OH_AVMuxer_SetRotation(OH_AVMuxer *muxer, int32_t rotation) {
struct AVMuxerObject *object = reinterpret_cast<AVMuxerObject *>(muxer);
CHECK_AND_RETURN_RET_LOG(object->muxer_ != nullptr, AV_ERR_INVALID_VAL, "muxer_ is nullptr!");
if (rotation != VIDEO_ROTATION_0 && rotation != VIDEO_ROTATION_90 &&
rotation != VIDEO_ROTATION_180 &&rotation != VIDEO_ROTATION_270) {
CHECK_AND_RETURN_RET_LOG(false, AV_ERR_INVALID_VAL, "rotation is invalid value!");
}
int32_t ret = object->muxer_->SetRotation(rotation);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "muxer_ SetRotation failed!");
return AV_ERR_OK;
}
OH_AVErrCode OH_AVMuxer_AddTrack(OH_AVMuxer *muxer, uint32_t *trackIndex, OH_AVFormat *trackFormat) {
OH_AVErrCode OH_AVMuxer_AddTrack(OH_AVMuxer *muxer, int32_t *trackIndex, OH_AVFormat *trackFormat) {
CHECK_AND_RETURN_RET_LOG(muxer != nullptr, AV_ERR_INVALID_VAL, "input muxer is nullptr!");
CHECK_AND_RETURN_RET_LOG(muxer->magic_ == AVMagic::AVCODEC_MAGIC_AVMUXER, AV_ERR_INVALID_VAL, "magic error!");
CHECK_AND_RETURN_RET_LOG(trackIndex != nullptr, AV_ERR_INVALID_VAL, "input track index is nullptr!");
CHECK_AND_RETURN_RET_LOG(trackFormat != nullptr, AV_ERR_INVALID_VAL, "input track format is nullptr!");
CHECK_AND_RETURN_RET_LOG(trackFormat->magic_ == AVMagic::AVCODEC_MAGIC_AVMUXER, AV_ERR_INVALID_VAL, "magic error!");
CHECK_AND_RETURN_RET_LOG(trackFormat->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, AV_ERR_INVALID_VAL, "magic error!");
struct AVMuxerObject *object = reinterpret_cast<AVMuxerObject *>(muxer);
CHECK_AND_RETURN_RET_LOG(object->muxer_ != nullptr, AV_ERR_INVALID_VAL, "muxer_ is nullptr!");
@ -106,11 +102,14 @@ OH_AVErrCode OH_AVMuxer_WriteSampleBuffer(OH_AVMuxer *muxer, uint32_t trackIndex
struct AVMuxerObject *object = reinterpret_cast<AVMuxerObject *>(muxer);
CHECK_AND_RETURN_RET_LOG(object->muxer_ != nullptr, AV_ERR_INVALID_VAL, "muxer_ is nullptr!");
AVCodecBufferInfo innerInfo;
innerInfo.presentationTimeUs = info.pts;
innerInfo.offset = info.offset;
innerInfo.size = info.size;
int32_t ret = object->muxer_->WriteSampleBuffer(trackIndex, sampleBuffer, innerInfo);
TrackSampleInfo sampleInfo;
sampleInfo.trackIndex = trackIndex;
sampleInfo.timeUs = info.pts;
sampleInfo.size = info.size;
sampleInfo.flags = info.flags;
int32_t ret = object->muxer_->WriteSampleBuffer(sampleBuffer, sampleInfo);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "muxer_ WriteSampleBuffer failed!");
return AV_ERR_OK;

View File

@ -21,7 +21,6 @@
#include "avsharedmemory.h"
#include "avcodec_common.h"
#include "format.h"
#include "avcodec_info.h"
#define AV_MAGIC(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + ((d) << 0))

View File

@ -100,6 +100,16 @@ config("av_codec_client_local_config") {
]
}
config("av_codec_client_ipc_config") {
include_dirs = [
"$AV_CODEC_ROOT_DIR/services/services/sa_avcodec/client",
"$AV_CODEC_ROOT_DIR/services/services/sa_avcodec/ipc",
"$AV_CODEC_ROOT_DIR/services/services/common",
"$AV_CODEC_ROOT_DIR/services/services/muxer/client",
"$AV_CODEC_ROOT_DIR/services/services/muxer/ipc",
]
}
config("av_codec_client_public_config") {
include_dirs = [
"$AV_CODEC_ROOT_DIR/frameworks/native/avcodec",
@ -111,6 +121,7 @@ config("av_codec_client_public_config") {
"$AV_CODEC_ROOT_DIR/services/utils",
"$AV_CODEC_ROOT_DIR/services/include",
"$AV_CODEC_ROOT_DIR/services/dfx/include",
"$AV_CODEC_ROOT_DIR/services/utils/include",
"//base/hiviewdfx/hilog/interfaces/native/innerkits/include",
"//utils/system/safwk/native/include",
"//third_party/bounds_checking_function/include",
@ -159,6 +170,7 @@ ohos_shared_library("av_codec_client") {
install_enable = true
public_configs = [
":av_codec_client_local_config",
":av_codec_client_ipc_config",
":av_codec_client_public_config",
":av_codec_packege_include",
]
@ -202,8 +214,8 @@ ohos_shared_library("av_codec_client") {
if (multimedia_av_codec_support_muxer) {
sources += [
"$AV_CODEC_ROOT_DIR/frameworks/native/avmuxer/avmuxer_impl.cpp",
"$AV_CODEC_ROOT_DIR/services/services/muxer/client/avmuxer_client.cpp",
"$AV_CODEC_ROOT_DIR/services/services/muxer/ipc/avmuxer_proxy.cpp",
"$AV_CODEC_ROOT_DIR/services/services/muxer/client/muxer_client.cpp",
"$AV_CODEC_ROOT_DIR/services/services/muxer/ipc/muxer_service_proxy.cpp",
]
}

View File

@ -118,20 +118,20 @@ enum AVSeekMode : uint8_t {
*/
enum VideoRotation : uint32_t {
/**
* Video without rotation
*/
* Video without rotation
*/
VIDEO_ROTATION_0 = 0,
/**
* Video rotated 90 degrees
*/
* Video rotated 90 degrees
*/
VIDEO_ROTATION_90 = 90,
/**
* Video rotated 180 degrees
*/
* Video rotated 180 degrees
*/
VIDEO_ROTATION_180 = 180,
/**
* Video rotated 270 degrees
*/
* Video rotated 270 degrees
*/
VIDEO_ROTATION_270 = 270,
};
@ -151,6 +151,53 @@ enum StateChangeReason {
*/
BACKGROUND = 2,
};
/**
* @brief Enumerates the output format.
*
* @since 10
* @version 4.0
*/
enum OutputFormat : uint32_t{
/**
* output format unknown
*/
OUTPUT_FORMAT_UNKNOWN = 0,
/**
* output format mp4
*/
OUTPUT_FORMAT_MPEG_4 = 1,
/**
* output format m4a
*/
OUTPUT_FORMAT_M4A = 2,
};
/**
* @brief Description information of a sample associated a media track.
*
* @since 10
* @version 4.0
*/
struct TrackSampleInfo {
/**
* @brief the id of track that this sample belongs to.
*/
uint32_t trackIndex;
/**
* @brief the presentation timestamp in microseconds.
*/
int64_t timeUs;
/**
* @brief the size in bytes.
*/
uint32_t size;
/**
* @brief the flags associated with the sample, this
* maybe be a combination of multiple {@link AVCodecBufferFlag}.
*/
uint32_t flags;
};
} // namespace Media
} // namespace OHOS
#endif // AV_COMMOM_H

View File

@ -57,16 +57,11 @@ struct AVCodecBufferInfo {
int32_t offset = 0;
};
typedef enum AVOutputFormat {
AV_OUTPUT_FORMAT_UNKNOWN = 0,
AV_OUTPUT_FORMAT_MPEG_4 = 1,
AV_OUTPUT_FORMAT_M4A = 2,
} AVOutputFormat;
struct AVBufferElement {
std::shared_ptr<AVSharedMemory> buffer;
std::shared_ptr<AVSharedMemory> metaData;
};
class AVCodecCallback {
public:
virtual ~AVCodecCallback() = default;

View File

@ -16,7 +16,6 @@
#ifndef AVCODEC_ERRORS_H
#define AVCODEC_ERRORS_H
#include <map>
#include <string>
#include "errors.h"
#include "native_averrors.h"

View File

@ -508,6 +508,9 @@ public:
static constexpr std::string_view AUDIO_OPUS = "audio/opus";
static constexpr std::string_view AUDIO_FLAC = "audio/flac";
static constexpr std::string_view AUDIO_RAW = "audio/raw";
static constexpr std::string_view IMAGE_JPG = "image/jpeg";
static constexpr std::string_view IMAGE_PNG = "image/png";
static constexpr std::string_view IMAGE_BMP = "image/bmp";
};
/**

View File

@ -16,9 +16,8 @@
#ifndef AVMUXER_H
#define AVMUXER_H
#include "format.h"
#include "avcodec_errors.h"
#include "avcodec_common.h"
#include "media_description.h"
#include "av_common.h"
namespace OHOS {
namespace Media {
@ -27,21 +26,20 @@ public:
virtual ~AVMuxer() = default;
virtual int32_t SetLocation(float latitude, float longitude) = 0;
virtual int32_t SetRotation(int32_t rotation) = 0;
virtual int32_t SetParameter(const Format &generalFormat) = 0;
virtual int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) = 0;
virtual int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) = 0;
virtual int32_t Start() = 0;
virtual int32_t WriteSampleBuffer(uint32_t trackIndex, uint8_t *sampleBuffer, AVCodecBufferInfo info) = 0;
virtual int32_t WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info) = 0;
virtual int32_t Stop() = 0;
};
class __attribute__((visibility("default"))) AVMuxerFactory {
public:
static std::shared_ptr<AVMuxer> CreateAVMuxer(int32_t fd, AVOutputFormat format);
static std::shared_ptr<AVMuxer> CreateAVMuxer(int32_t fd, OutputFormat format);
private:
AVMuxerFactory() = default;
~AVMuxerFactory() = default;
};
} // namespace MediaAVCodec
} // namespace Media
} // namespace OHOS
#endif // AVMUXER_H

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Huawei Device Co., Ltd.
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Huawei Device Co., Ltd.
* 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
@ -68,7 +68,7 @@ public:
* @param key Indicates the metadata key.
* @param value Indicates the metadata value, which is a 32-bit integer.
* @return Returns <b>true</b> if the setting is successful; returns <b>false</b> otherwise.
* @since 1.0
* @since 10
* @version 1.0
*/
bool PutIntValue(const std::string_view &key, int32_t value);
@ -79,7 +79,7 @@ public:
* @param key Indicates the metadata key.
* @param value Indicates the metadata value, which is a 64-bit integer.
* @return Returns <b>true</b> if the setting is successful; returns <b>false</b> otherwise.
* @since 1.0
* @since 10
* @version 1.0
*/
bool PutLongValue(const std::string_view &key, int64_t value);
@ -90,7 +90,7 @@ public:
* @param key Indicates the metadata key.
* @param value Indicates the metadata value, which is a single-precision floating-point number.
* @return Returns <b>true</b> if the metadata is successfully set; returns <b>false</b> otherwise.
* @since 1.0
* @since 10
* @version 1.0
*/
bool PutFloatValue(const std::string_view &key, float value);
@ -101,7 +101,7 @@ public:
* @param key Indicates the metadata key.
* @param value Indicates the metadata value, which is a double-precision floating-point number.
* @return Returns <b>true</b> if the setting is successful; returns <b>false</b> otherwise.
* @since 1.0
* @since 10
* @version 1.0
*/
bool PutDoubleValue(const std::string_view &key, double value);
@ -112,7 +112,7 @@ public:
* @param key Indicates the metadata key.
* @param value Indicates the metadata value, which is a string.
* @return Returns <b>true</b> if the metadata is successfully set; returns <b>false</b> otherwise.
* @since 1.0
* @since 10
* @version 1.0
*/
bool PutStringValue(const std::string_view &key, const std::string_view &value);
@ -124,7 +124,7 @@ public:
* @param addr Indicates the metadata addr, which is a uint8_t *.
* @param size Indicates the metadata addr size, which is a size_t.
* @return Returns <b>true</b> if the metadata is successfully set; returns <b>false</b> otherwise.
* @since 1.0
* @since 10
* @version 1.0
*/
bool PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size);
@ -135,7 +135,7 @@ public:
* @param key Indicates the metadata key.
* @param value Indicates the metadata value to obtain, which is a 32-bit integer.
* @return Returns <b>true</b> if the integer is successfully obtained; returns <b>false</b> otherwise.
* @since 1.0
* @since 10
* @version 1.0
*/
bool GetIntValue(const std::string_view &key, int32_t &value) const;
@ -146,7 +146,7 @@ public:
* @param key Indicates the metadata key.
* @param value Indicates the metadata value to obtain, which is a 64-bit long integer.
* @return Returns <b>true</b> if the integer is successfully obtained; returns <b>false</b> otherwise.
* @since 1.0
* @since 10
* @version 1.0
*/
bool GetLongValue(const std::string_view &key, int64_t &value) const;
@ -158,7 +158,7 @@ public:
* @param value Indicates the metadata value to obtain, which is a single-precision floating-point number.
* @return Returns <b>true</b> if the single-precision number is successfully obtained; returns
* <b>false</b> otherwise.
* @since 1.0
* @since 10
* @version 1.0
*/
bool GetFloatValue(const std::string_view &key, float &value) const;
@ -170,7 +170,7 @@ public:
* @param value Indicates the metadata value to obtain, which is a double-precision floating-point number.
* @return Returns <b>true</b> if the double-precision number is successfully obtained; returns
* <b>false</b> otherwise.
* @since 1.0
* @since 10
* @version 1.0
*/
bool GetDoubleValue(const std::string_view &key, double &value) const;
@ -181,7 +181,7 @@ public:
* @param key Indicates the metadata key.
* @param value Indicates the metadata value to obtain, which is a string.
* @return Returns <b>true</b> if the string is successfully obtained; returns <b>false</b> otherwise.
* @since 1.0
* @since 10
* @version 1.0
*/
bool GetStringValue(const std::string_view &key, std::string &value) const;
@ -193,7 +193,7 @@ public:
* @param addr Indicates the metadata addr to obtain, which is a uint8_t **.
* @param size Indicates the metadata addr size to obtain, which is a size_t.
* @return Returns <b>true</b> if the string is successfully obtained; returns <b>false</b> otherwise.
* @since 1.0
* @since 10
* @version 1.0
*/
bool GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) const;
@ -233,7 +233,7 @@ public:
* @brief Obtains the metadata map.
*
* @return Returns the map object.
* @since 1.0
* @since 10
* @version 1.0
*/
const FormatDataMap &GetFormatMap() const;
@ -242,7 +242,7 @@ public:
* @brief Convert the metadata map to string.
*
* @return Returns a converted string.
* @since 1.0
* @since 10
* @version 1.0
*/
std::string Stringify() const;

View File

@ -0,0 +1,136 @@
/*
* Copyright (C) 2021 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.
*/
#ifndef MEDIA_DESCRIPTION_H
#define MEDIA_DESCRIPTION_H
#include "format.h"
namespace OHOS {
namespace Media {
/**
* @brief Provides the uniform container for storing the media description.
*/
using MediaDescription = Format;
/**
* @brief Provides the key's definition for MediaDescription.
*/
class MediaDescriptionKey {
public:
/**
* Key for track index, value type is uint32_t
*/
static constexpr std::string_view MD_KEY_TRACK_INDEX = "track_index";
/**
* Key for track type, value type is uint8_t, see {link @MediaTrackType}
*/
static constexpr std::string_view MD_KEY_TRACK_TYPE = "track_type";
/**
* Key for codec mime type, value type is string
*/
static constexpr std::string_view MD_KEY_CODEC_MIME = "codec_mime";
/**
* Key for duration, value type is int64_t
*/
static constexpr std::string_view MD_KEY_DURATION = "duration";
/**
* Key for bitrate, value type is uint32_t
*/
static constexpr std::string_view MD_KEY_BITRATE = "bitrate";
/**
* Key for max input size, value type is uint32_t
*/
static constexpr std::string_view MD_KEY_MAX_INPUT_SIZE = "max_input_size";
/**
* Key for video width, value type is uint32_t
*/
static constexpr std::string_view MD_KEY_WIDTH = "width";
/**
* Key for video height, value type is uint32_t
*/
static constexpr std::string_view MD_KEY_HEIGHT = "height";
/**
* Key for video pixelformat, value type is int32_t, see {link @MediaPixelFormat}
*/
static constexpr std::string_view MD_KEY_PIXEL_FORMAT = "pixel_format";
/**
* Key for video frame rate, value type is double.
*/
static constexpr std::string_view MD_KEY_FRAME_RATE = "frame_rate";
/**
* Key for video capture rate, value type is double
*/
static constexpr std::string_view MD_KEY_CAPTURE_RATE = "capture_rate";
/**
* Key for the interval of key frame. value type is int32_t, the unit is milliseconds.
* A negative value means no key frames are requested after the first frame. A zero
* value means a stream containing all key frames is requested.
*/
static constexpr std::string_view MD_KEY_I_FRAME_INTERVAL = "i_frame_interval";
/**
* Key for the request a I-Frame immediately. value type is boolean
*/
static constexpr std::string_view MD_KEY_REQUEST_I_FRAME = "req_i_frame";
/**
* Key for audio channel count, value type is uint32_t
*/
static constexpr std::string_view MD_KEY_CHANNEL_COUNT = "channel_count";
/**
* Key for audio sample rate, value type is uint32_t
*/
static constexpr std::string_view MD_KEY_SAMPLE_RATE = "sample_rate";
/**
* Key for track count in the container, value type is uint32_t
*/
static constexpr std::string_view MD_KEY_TRACK_COUNT = "track_count";
/**
* Key for container format type, value type is string
*/
static constexpr std::string_view MD_KEY_CONTAINER_FORMAT = "container_format";
/**
* custom key prefix, media service will pass through to HAL.
*/
static constexpr std::string_view MD_KEY_CUSTOM_PREFIX = "vendor.custom";
/**
* Key for codec specific data buffer, vlaue type is uint8_t*
*/
static constexpr std::string_view MD_KEY_CODEC_CONFIG = "codec_config";
private:
MediaDescriptionKey() = delete;
~MediaDescriptionKey() = delete;
};
} // namespace Media
} // namespace OHOS
#endif // MEDIA_DESCRIPTION_H

View File

@ -206,6 +206,9 @@ ohos_shared_library("native_av_codec_codec") {
ohos_shared_library("native_av_codec_avmuxer") {
install_enable = true
sources = [
"$AV_CODEC_ROOT_DIR/frameworks/native/capi/avcodec/native_avcodec_base.cpp",
"$AV_CODEC_ROOT_DIR/frameworks/native/capi/common/native_avformat.cpp",
"$AV_CODEC_ROOT_DIR/frameworks/native/capi/common/native_avmemory.cpp",
"$AV_CODEC_ROOT_DIR/frameworks/native/capi/avmuxer/native_avmuxer.cpp",
]
@ -214,14 +217,11 @@ ohos_shared_library("native_av_codec_avmuxer") {
deps = [
"//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client",
"//foundation/multimedia/av_codec/services/utils:av_codec_format",
"//foundation/multimedia/av_codec/interfaces/kits/c:native_av_codec_core",
]
external_deps = [
"c_utils:utils",
"graphic_standard:surface",
"hiviewdfx_hilog_native:libhilog",
"graphic_standard:surface",
]
output_extension = "so"
subsystem_name = "multimedia"

View File

@ -1,4 +1,4 @@
# Copyright (C) 2022 Huawei Device Co., Ltd.
# 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
@ -20,6 +20,7 @@ ohos_ndk_headers("native_av_codec_avmuxer_header") {
"//foundation/multimedia/av_codec/interfaces/kits/c/native_avbase.h",
"//foundation/multimedia/av_codec/interfaces/kits/c/native_averrors.h",
"//foundation/multimedia/av_codec/interfaces/kits/c/native_avformat.h",
"//foundation/multimedia/av_codec/interfaces/kits/c/native_avmemory.h",
"//foundation/multimedia/av_codec/interfaces/kits/c/native_avmuxer.h",
]
}
@ -35,6 +36,7 @@ ohos_ndk_library("libnative_av_codec_avmuxer") {
"native_av_codec_avmuxer/native_avbase.h",
"native_av_codec_avmuxer/native_averrors.h",
"native_av_codec_avmuxer/native_avformat.h",
"native_av_codec_avmuxer/native_avmemory.h",
"native_av_codec_avmuxer/native_avmuxer.h",
]
}

View File

@ -15,6 +15,8 @@
{ "name": "OH_AVFormat_GetStringValue" },
{ "name": "OH_AVFormat_GetBuffer" },
{ "name": "OH_AVFormat_DumpInfo" },
{ "name": "OH_AVMemory_GetAddr" },
{ "name": "OH_AVMemory_GetSize" },
{ "name": "OH_AVMuxer_Create" },
{ "name": "OH_AVMuxer_SetLocation" },
{ "name": "OH_AVMuxer_SetRotation" },

View File

@ -47,6 +47,18 @@ typedef enum OH_AVCodecBufferFlags {
AVCODEC_BUFFER_FLAGS_CODEC_DATA = 1 << 3,
} OH_AVCodecBufferFlags;
/**
* @brief Enumerates the muxer ouputfile format
*
* @since 10
* @version 1.0
*/
typedef enum OH_AVOutputFormat {
AV_OUTPUT_FORMAT_UNKNOWN = 0,
AV_OUTPUT_FORMAT_MPEG_4 = 1,
AV_OUTPUT_FORMAT_M4A = 2,
} OH_AVOutputFormat;
/**
* @brief Define the Buffer description information of OH_AVCodec
* @syscap SystemCapability.Multimedia.Media.CodecBase
@ -64,18 +76,6 @@ typedef struct OH_AVCodecBufferAttr {
uint32_t flags;
} OH_AVCodecBufferAttr;
/**
* @brief Enumerates the muxer ouputfile format
*
* @since 10
* @version 1.0
*/
typedef enum OH_AVOutputFormat {
AV_OUTPUT_FORMAT_UNKNOWN = 0,
AV_OUTPUT_FORMAT_MPEG_4 = 1,
AV_OUTPUT_FORMAT_M4A = 2,
} OH_AVOutputFormat;
/**
* @brief When an error occurs in the running of the OH_AVCodec instance, the function pointer will be called
* to report specific error information.
@ -157,7 +157,12 @@ typedef struct OH_AVCodecAsyncCallback {
* @version 1.0
*/
extern const char *OH_AVCODEC_MIMETYPE_VIDEO_AVC;
extern const char *OH_AVCODEC_MIMETYPE_VIDEO_MPEG4;
extern const char *OH_AVCODEC_MIMETYPE_AUDIO_AAC;
extern const char *OH_AVCODEC_MIMETYPE_AUDIO_MPEG;
extern const char *OH_AVCODEC_MIMETYPE_IMAGE_JPG;
extern const char *OH_AVCODEC_MIMETYPE_IMAGE_PNG;
extern const char *OH_AVCODEC_MIMETYPE_IMAGE_BMP;
/**
* @brief The extra data's key of surface Buffer
@ -208,6 +213,8 @@ extern const char *OH_MD_KEY_AUD_SAMPLE_RATE;
extern const char *OH_MD_KEY_I_FRAME_INTERVAL;
/* Key of the surface rotation angle. value type is int32_t: should be {0, 90, 180, 270}, default is 0. */
extern const char *OH_MD_KEY_ROTATION;
/* Key of the codec specific data. value type is uint8_t*. */
extern const char *OH_MD_KEY_CODEC_CONFIG;
/**
* @brief Media type.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 Huawei Device Co., Ltd.
* 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
@ -21,8 +21,8 @@ extern "C" {
/**
* @brief AV error code
* @syscap SystemCapability.Multimedia.Media.Core
* @since 9
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @since 10
* @version 1.0
*/
typedef enum OH_AVErrCode {

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 Huawei Device Co., Ltd.
* 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
@ -26,219 +26,190 @@ extern "C" {
typedef struct OH_AVFormat OH_AVFormat;
/**
* @brief Enumerates AVPixel Format.
* @syscap SystemCapability.Multimedia.Media.Core
* @since 9
* @version 1.0
*/
typedef enum OH_AVPixelFormat {
/**
* yuv 420 planar.
*/
AV_PIXEL_FORMAT_YUVI420 = 1,
/**
* NV12. yuv 420 semiplanar.
*/
AV_PIXEL_FORMAT_NV12 = 2,
/**
* NV21. yvu 420 semiplanar.
*/
AV_PIXEL_FORMAT_NV21 = 3,
/**
* format from surface.
*/
AV_PIXEL_FORMAT_SURFACE_FORMAT = 4,
/**
* RGBA8888
*/
AV_PIXEL_FORMAT_RGBA = 5,
} OH_AVPixelFormat;
/**
* @briefCreate an OH_AVFormat handle pointer to read and write data
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @return Returns a pointer to an OH_AVFormat instance
* @since 9
* @since 10
* @version 1.0
*/
struct OH_AVFormat *OH_AVFormat_Create(void);
/**
* @brief Destroy the specified OH_AVFormat handle resource
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @return void
* @since 9
* @since 10
* @version 1.0
*/
void OH_AVFormat_Destroy(struct OH_AVFormat *format);
/**
* @brief Copy OH_AVFormat handle resource
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param to OH_AVFormat handle pointer to receive data
* @param from pointer to the OH_AVFormat handle of the copied data
* @return The return value is TRUE for success, FALSE for failure
* @since 9
* @since 10
* @version 1.0
*/
bool OH_AVFormat_Copy(struct OH_AVFormat *to, struct OH_AVFormat *from);
/**
* @brief Write Int data to OH_AVFormat
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @param key key to write data
* @param value written data
* @return The return value is TRUE for success, FALSE for failure
* @since 9
* @since 10
* @version 1.0
*/
bool OH_AVFormat_SetIntValue(struct OH_AVFormat *format, const char *key, int32_t value);
/**
* @brief Write Long data to OH_AVFormat
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @param key key to write data
* @param value written data
* @return The return value is TRUE for success, FALSE for failure
* @since 9
* @since 10
* @version 1.0
*/
bool OH_AVFormat_SetLongValue(struct OH_AVFormat *format, const char *key, int64_t value);
/**
* @brief Write Float data to OH_AVFormat
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @param key key to write data
* @param value written data
* @return The return value is TRUE for success, FALSE for failure
* @since 9
* @since 10
* @version 1.0
*/
bool OH_AVFormat_SetFloatValue(struct OH_AVFormat *format, const char *key, float value);
/**
* @brief Write Double data to OH_AVFormat
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @param key key to write data
* @param value written data
* @return The return value is TRUE for success, FALSE for failure
* @since 9
* @since 10
* @version 1.0
*/
bool OH_AVFormat_SetDoubleValue(struct OH_AVFormat *format, const char *key, double value);
/**
* @brief Write String data to OH_AVFormat
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @param key key to write data
* @param value written data
* @return The return value is TRUE for success, FALSE for failure
* @since 9
* @since 10
* @version 1.0
*/
bool OH_AVFormat_SetStringValue(struct OH_AVFormat *format, const char *key, const char *value);
/**
* @brief Writes a block of data of a specified length to OH_AVFormat
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @param key key to write data
* @param addr written data addr
* @param size written data length
* @return The return value is TRUE for success, FALSE for failure
* @since 9
* @since 10
* @version 1.0
*/
bool OH_AVFormat_SetBuffer(struct OH_AVFormat *format, const char *key, const uint8_t *addr, size_t size);
/**
* @brief Read Int data from OH_AVFormat
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @param key read key value
* @param out read data
* @return The return value is TRUE for success, FALSE for failure
* @since 9
* @since 10
* @version 1.0
*/
bool OH_AVFormat_GetIntValue(struct OH_AVFormat *format, const char *key, int32_t *out);
/**
* @brief Read Long data from OH_AVFormat
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @param key read key value
* @param out read data
* @return The return value is TRUE for success, FALSE for failure
* @since 9
* @since 10
* @version 1.0
*/
bool OH_AVFormat_GetLongValue(struct OH_AVFormat *format, const char *key, int64_t *out);
/**
* @brief Read Float data from OH_AVFormat
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @param key read key value
* @param out read data
* @return The return value is TRUE for success, FALSE for failure
* @since 9
* @since 10
* @version 1.0
*/
bool OH_AVFormat_GetFloatValue(struct OH_AVFormat *format, const char *key, float *out);
/**
* @brief Read Double data from OH_AVFormat
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @param key read key value
* @param out read data
* @return The return value is TRUE for success, FALSE for failure
* @since 9
* @since 10
* @version 1.0
*/
bool OH_AVFormat_GetDoubleValue(struct OH_AVFormat *format, const char *key, double *out);
/**
* @brief Read Double data from OH_AVFormat
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @param key read key value
* @param out The read string pointer, the data life cycle pointed to is updated with GetString,
* and Format is destroyed. If the caller needs to hold it for a long time, it must copy the memory
* @return The return value is TRUE for success, FALSE for failure
* @since 9
* @since 10
* @version 1.0
*/
bool OH_AVFormat_GetStringValue(struct OH_AVFormat *format, const char *key, const char **out);
/**
* @brief Read a block of data of specified length from OH_AVFormat
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @param key Key value for reading and writing data
* @param addr The life cycle is held by the format, with the destruction of the format,
* if the caller needs to hold it for a long time, it must copy the memory
* @param size Length of read and write data
* @return The return value is TRUE for success, FALSE for failure
* @since 9
* @since 10
* @version 1.0
*/
bool OH_AVFormat_GetBuffer(struct OH_AVFormat *format, const char *key, uint8_t **addr, size_t *size);
/**
* @brief Output the information contained in OH_AVFormat as a string.
* @syscap SystemCapability.Multimedia.Media.Core
* @syscap SystemCapability.Multimedia.Media.AVCodec
* @param format pointer to an OH_AVFormat instance
* @return Returns a string consisting of key and data
* @since 9
* @since 10
* @version 1.0
*/
const char *OH_AVFormat_DumpInfo(struct OH_AVFormat *format);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 Huawei Device Co., Ltd.
* 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
@ -29,7 +29,7 @@ typedef struct OH_AVMemory OH_AVMemory;
* @syscap SystemCapability.Multimedia.Media.Core
* @param mem Encapsulate OH_AVMemory structure instance pointer
* @return the memory's virtual address if the memory is valid, otherwise nullptr.
* @since 9
* @since 10
* @version 1.0
*/
uint8_t *OH_AVMemory_GetAddr(struct OH_AVMemory *mem);
@ -39,7 +39,7 @@ uint8_t *OH_AVMemory_GetAddr(struct OH_AVMemory *mem);
* @syscap SystemCapability.Multimedia.Media.Core
* @param mem Encapsulate OH_AVMemory structure instance pointer
* @return the memory's size if the memory is valid, otherwise -1.
* @since 9
* @since 10
* @version 1.0
*/
int32_t OH_AVMemory_GetSize(struct OH_AVMemory *mem);

View File

@ -74,15 +74,16 @@ OH_AVErrCode OH_AVMuxer_SetRotation(OH_AVMuxer *muxer, int32_t rotation);
* Note: This interface can only be called before OH_AVMuxer_Start.
* @syscap SystemCapability.Multimedia.Media.AVMuxer
* @param muxer Pointer to an OH_AVMuxer instance
* @param trackIndex The uint32_t handle pointer used to get the track index for this newly added track,
* and it should be used in the OH_AVMuxer_WriteSampleBuffer. The track index is greater than or equal to 0.
* @param trackIndex The int32_t handle pointer used to get the track index for this newly added track,
* and it should be used in the OH_AVMuxer_WriteSampleBuffer. The track index is greater than or equal to 0,
* others is error index.
* @param trackFormat OH_AVFormat handle pointer contain track format
* @return Returns AV_ERR_OK if the execution is successful,
* otherwise returns a specific error code, refer to {@link OH_AVErrCode}
* @since 10
* @version 1.0
*/
OH_AVErrCode OH_AVMuxer_AddTrack(OH_AVMuxer *muxer, uint32_t *trackIndex, OH_AVFormat *trackFormat);
OH_AVErrCode OH_AVMuxer_AddTrack(OH_AVMuxer *muxer, int32_t *trackIndex, OH_AVFormat *trackFormat);
/**
* @brief Start the muxer.

View File

@ -16,8 +16,6 @@ import("//build/ohos.gni")
group("av_codec_services_package") {
deps = [
"etc:av_codec_service.cfg",
"engine:av_codec_engine_package",
"services:av_codec_service",
]
}

View File

@ -16,7 +16,7 @@ import("//foundation/multimedia/av_codec/config.gni")
group("av_codec_engine_package") {
deps = [
"plugin:av_codec_engine_plugins",
"plugin:av_codec_plugin",
#"avcodeclist:av_codec_engine_avcodeclist",
]
}

View File

@ -0,0 +1,364 @@
/*
* 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 "muxer_engine_impl.h"
#include <set>
#include <fcntl.h>
#include <unistd.h>
#include "securec.h"
#include "avcodec_log.h"
#include "muxer_factory.h"
#include "avcodec_dfx.h"
#include "avcodec_info.h"
#include "avcodec_errors.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MuxerEngineImpl"};
constexpr int32_t MAX_LATITUDE = 90;
constexpr int32_t MIN_LATITUDE = -90;
constexpr int32_t MAX_LONGITUDE = 180;
constexpr int32_t MIN_LONGITUDE = -180;
constexpr int32_t ERR_TRACK_INDEX = -1;
}
namespace OHOS {
namespace Media {
const std::map<uint32_t, std::set<std::string_view>> MUX_FORMAT_INFO = {
{OUTPUT_FORMAT_MPEG_4, {CodecMimeType::AUDIO_MPEG, CodecMimeType::AUDIO_AAC,
CodecMimeType::VIDEO_AVC, CodecMimeType::VIDEO_MPEG4,
CodecMimeType::IMAGE_JPG, CodecMimeType::IMAGE_PNG, CodecMimeType::IMAGE_BMP}},
{OUTPUT_FORMAT_M4A, {CodecMimeType::AUDIO_AAC,
CodecMimeType::VIDEO_AVC, CodecMimeType::VIDEO_MPEG4,
CodecMimeType::IMAGE_JPG, CodecMimeType::IMAGE_PNG, CodecMimeType::IMAGE_BMP}},
};
const std::map<std::string_view, std::set<std::string_view>> MUX_MIME_INFO = {
{CodecMimeType::AUDIO_MPEG, {MediaDescriptionKey::MD_KEY_SAMPLE_RATE, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT}},
{CodecMimeType::AUDIO_AAC, {MediaDescriptionKey::MD_KEY_SAMPLE_RATE, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT}},
{CodecMimeType::VIDEO_AVC, {MediaDescriptionKey::MD_KEY_WIDTH, MediaDescriptionKey::MD_KEY_HEIGHT}},
{CodecMimeType::VIDEO_MPEG4, {MediaDescriptionKey::MD_KEY_WIDTH, MediaDescriptionKey::MD_KEY_HEIGHT}},
{CodecMimeType::IMAGE_JPG, {MediaDescriptionKey::MD_KEY_WIDTH, MediaDescriptionKey::MD_KEY_HEIGHT}},
{CodecMimeType::IMAGE_PNG, {MediaDescriptionKey::MD_KEY_WIDTH, MediaDescriptionKey::MD_KEY_HEIGHT}},
{CodecMimeType::IMAGE_BMP, {MediaDescriptionKey::MD_KEY_WIDTH, MediaDescriptionKey::MD_KEY_HEIGHT}},
};
std::shared_ptr<IMuxerEngine> IMuxerEngineFactory::CreateMuxerEngine(int32_t appUid, int32_t appPid, int32_t fd, OutputFormat format)
{
AVCodecTrace trace("IMuxerEngineFactory::CreateMuxerEngine");
CHECK_AND_RETURN_RET_LOG((fcntl(fd, F_GETFL, 0) & O_RDWR) == O_RDWR, nullptr, "no permission to read and write fd");
CHECK_AND_RETURN_RET_LOG(lseek(fd, 0, SEEK_CUR) != -1, nullptr, "the fd is not seekable");
std::shared_ptr<IMuxerEngine> muxerEngineImpl = std::make_shared<MuxerEngineImpl>(appUid, appPid, fd, format);
CHECK_AND_RETURN_RET_LOG(muxerEngineImpl != nullptr, nullptr, "create MuxerEngine implementation failed");
return muxerEngineImpl;
}
MuxerEngineImpl::MuxerEngineImpl(int32_t appUid, int32_t appPid, int32_t fd, OutputFormat format)
: appUid_(appUid), appPid_(appPid), fd_(fd), format_(format), que_("muxer_write_queue")
{
AVCodecTrace trace("MuxerEngine::Create");
AVCODEC_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
muxer_ = Plugin::MuxerFactory::Instance().CreatePlugin(fd_, format_);
if (muxer_ != nullptr && fd_ >= 0) {
state_ = INITIALIZED;
AVCODEC_LOGI("state_ is INITIALIZED");
} else {
AVCODEC_LOGE("state_ is UNINITIALIZED");
}
}
MuxerEngineImpl::~MuxerEngineImpl()
{
AVCODEC_LOGD("Destroy");
if (state_ == STARTED) {
que_.SetActive(false);
StopThread();
}
appUid_ = -1;
appPid_ = -1;
muxer_ = nullptr;
tracks_.clear();
AVCODEC_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
}
int32_t MuxerEngineImpl::SetLocation(float latitude, float longitude)
{
AVCodecTrace trace("MuxerEngine::SetLocation");
AVCODEC_LOGI("SetLocation");
std::unique_lock<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(state_ == INITIALIZED, AVCS_ERR_INVALID_OPERATION,
"The state is not INITIALIZED, the interface must be called after constructor and before Start(). "
"The current state is %{public}s", ConvertStateToString(state_).c_str());
if (latitude < MIN_LATITUDE || latitude > MAX_LATITUDE ||
longitude < MIN_LONGITUDE || longitude > MAX_LONGITUDE) {
AVCODEC_LOGW("Invalid GeoLocation, latitude must be greater than %{public}d and less than %{public}d,"
"longitude must be greater than %{public}d and less than %{public}d",
MIN_LATITUDE, MAX_LATITUDE, MIN_LONGITUDE, MAX_LONGITUDE);
return AVCS_ERR_INVALID_VAL;
}
return TranslatePluginStatus(muxer_->SetLocation(latitude, longitude));
}
int32_t MuxerEngineImpl::SetRotation(int32_t rotation)
{
AVCodecTrace trace("MuxerEngine::SetRotation");
AVCODEC_LOGI("SetRotation");
std::unique_lock<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(state_ == INITIALIZED, AVCS_ERR_INVALID_OPERATION,
"The state is not INITIALIZED, the interface must be called after constructor and before Start(). "
"The current state is %{public}s", ConvertStateToString(state_).c_str());
if (rotation != VIDEO_ROTATION_0 && rotation != VIDEO_ROTATION_90 &&
rotation != VIDEO_ROTATION_180 && rotation != VIDEO_ROTATION_270) {
AVCODEC_LOGW("Invalid rotation: %{public}d, keep default 0", rotation);
return AVCS_ERR_INVALID_VAL;
}
return TranslatePluginStatus(muxer_->SetRotation(rotation));
}
int32_t MuxerEngineImpl::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc)
{
AVCodecTrace trace("MuxerEngine::AddTrack");
AVCODEC_LOGI("AddTrack");
std::unique_lock<std::mutex> lock(mutex_);
trackIndex = ERR_TRACK_INDEX;
CHECK_AND_RETURN_RET_LOG(state_ == INITIALIZED, AVCS_ERR_INVALID_OPERATION,
"The state is not INITIALIZED, the interface must be called after constructor and before Start(). "
"The current state is %{public}s", ConvertStateToString(state_).c_str());
std::string mimeType = {};
CHECK_AND_RETURN_RET_LOG(trackDesc.GetStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, mimeType),
AVCS_ERR_INVALID_VAL, "track format does not contain mime");
CHECK_AND_RETURN_RET_LOG(CanAddTrack(mimeType), AVCS_ERR_UNSUPPORT_CONTAINER_TYPE,
"track mime is unsupported: %{public}s", mimeType.c_str());
CHECK_AND_RETURN_RET_LOG(CheckKeys(mimeType, trackDesc), AVCS_ERR_INVALID_VAL,
"track format keys not contained");
int32_t trackId = -1;
Plugin::Status ret = muxer_->AddTrack(trackId, trackDesc);
CHECK_AND_RETURN_RET_LOG(ret == Plugin::Status::NO_ERROR, TranslatePluginStatus(ret), "AddTrack failed");
CHECK_AND_RETURN_RET_LOG(trackId >= 0, AVCS_ERR_INVALID_OPERATION,
"The track index is greater than or equal to 0, less than 99");
trackIndex = trackId;
tracks_[trackIndex] = mimeType;
return AVCS_ERR_OK;
}
int32_t MuxerEngineImpl::Start()
{
AVCodecTrace trace("MuxerEngine::Start");
AVCODEC_LOGI("Start");
std::unique_lock<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(state_ == INITIALIZED, AVCS_ERR_INVALID_OPERATION,
"The state is not INITIALIZED, the interface must be called after AddTrack() and before WriteSampleBuffer(). "
"The current state is %{public}s", ConvertStateToString(state_).c_str());
CHECK_AND_RETURN_RET_LOG(tracks_.size() > 0, AVCS_ERR_INVALID_OPERATION,
"The track count is error, count is %{public}d", tracks_.size());
Plugin::Status ret = muxer_->Start();
CHECK_AND_RETURN_RET_LOG(ret == Plugin::Status::NO_ERROR, TranslatePluginStatus(ret), "Start failed");
state_ = STARTED;
StartThread("muxer_write_loop");
return AVCS_ERR_OK;
}
int32_t MuxerEngineImpl::WriteSampleBuffer(std::shared_ptr<AVSharedMemory> sampleBuffer, const TrackSampleInfo &info)
{
AVCodecTrace trace("MuxerEngine::WriteSampleBuffer");
std::unique_lock<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(state_ == STARTED, AVCS_ERR_INVALID_OPERATION,
"The state is not STARTED, the interface must be called after Start() and before Stop(). "
"The current state is %{public}s", ConvertStateToString(state_).c_str());
CHECK_AND_RETURN_RET_LOG(tracks_.find(info.trackIndex) != tracks_.end(), AVCS_ERR_INVALID_VAL,
"The track index does not exist");
CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr && info.timeUs >= 0, AVCS_ERR_INVALID_VAL, "Invalid memory");
std::shared_ptr<BlockBuffer> blockBuffer = std::make_shared<BlockBuffer>();
blockBuffer->buffer_ = sampleBuffer;
blockBuffer->info_ = info;
que_.Push(blockBuffer);
return AVCS_ERR_OK;
}
int32_t MuxerEngineImpl::Stop()
{
AVCodecTrace trace("MuxerEngine::Stop");
AVCODEC_LOGI("Stop");
std::unique_lock<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(state_ == STARTED, AVCS_ERR_INVALID_OPERATION,
"The state is not STARTED. The current state is %{public}s", ConvertStateToString(state_).c_str());
state_ = STOPPED;
que_.SetActive(false, false);
cond_.wait(lock, [this] { return que_.Empty(); });
StopThread();
return TranslatePluginStatus(muxer_->Stop());
}
int32_t MuxerEngineImpl::DumpInfo(int32_t fd)
{
std::string dumpString;
dumpString += "In MuxerEngine::DumpInfo\n";
dumpString += "Current MuxerEngine state is: " + ConvertStateToString(state_) + "\n";
dumpString += "Current MuxerEngine output format is: " + std::to_string(format_) + "\n";
write(fd, dumpString.c_str(), dumpString.size());
return AVCS_ERR_OK;
}
int32_t MuxerEngineImpl::StartThread(std::string name)
{
threadName_ = name;
if (thread_ != nullptr) {
AVCODEC_LOGW("Started already! [%{public}s]", threadName_.c_str());
return AVCS_ERR_OK;
}
isThreadExit_ = false;
thread_ = std::make_unique<std::thread>(&MuxerEngineImpl::ThreadProcessor, this);
AVCodecTrace::TraceBegin("muxer_write_thread", FAKE_POINTER(thread_.get()));
AVCODEC_LOGD("thread started! [%{public}s]", threadName_.c_str());
return AVCS_ERR_OK;
}
int32_t MuxerEngineImpl::StopThread() noexcept
{
if (isThreadExit_) {
AVCODEC_LOGD("Stopped already! [%{public}s]", threadName_.c_str());
return AVCS_ERR_OK;
}
if (std::this_thread::get_id() == thread_->get_id()) {
AVCODEC_LOGD("Stop at the task thread, reject");
return AVCS_ERR_INVALID_OPERATION;
}
std::unique_ptr<std::thread> t;
isThreadExit_ = true;
cond_.notify_all();
std::swap(thread_, t);
if (t != nullptr && t->joinable()) {
t->join();
}
thread_ = nullptr;
return AVCS_ERR_OK;
}
void MuxerEngineImpl::ThreadProcessor()
{
AVCODEC_LOGD("Enter ThreadProcessor [%{public}s]", threadName_.c_str());
constexpr uint32_t nameSizeMax = 15;
pthread_setname_np(pthread_self(), threadName_.substr(0, nameSizeMax).c_str());
int32_t taskId = FAKE_POINTER(thread_.get());
for (;;) {
AVCodecTrace trace(threadName_);
if (isThreadExit_) {
AVCodecTrace::TraceEnd("muxer_write_thread", taskId);
AVCODEC_LOGD("Exit ThreadProcessor [%{public}s]", threadName_.c_str());
return;
}
auto buffer = que_.Pop();
if (buffer != nullptr) {
(void)muxer_->WriteSampleBuffer(buffer->buffer_->GetBase(), buffer->info_);
}
if (que_.Empty()) {
cond_.notify_all();
}
}
}
bool MuxerEngineImpl::CanAddTrack(std::string &mimeType)
{
auto it = MUX_FORMAT_INFO.find(format_);
if (it == MUX_FORMAT_INFO.end()) {
return false;
}
return it->second.find(mimeType) != it->second.end();
}
bool MuxerEngineImpl::CheckKeys(std::string &mimeType, const MediaDescription &trackDesc)
{
bool ret = true;
auto it = MUX_MIME_INFO.find(mimeType);
if (it == MUX_MIME_INFO.end()) {
return ret; // 不做检查
}
for (auto &key : it->second) {
if(!trackDesc.ContainKey(key)) {
ret = false;
AVCODEC_LOGE("the MediaDescriptionKey %{public}s not contained", key.data());
}
}
return ret;
}
std::string MuxerEngineImpl::ConvertStateToString(int32_t state)
{
std::string stateInfo {};
switch (state)
{
case UNINITIALIZED:
stateInfo = "UNINITIALIZED";
break;
case INITIALIZED:
stateInfo = "INITIALIZED";
break;
case STARTED:
stateInfo = "STARTED";
break;
case STOPPED:
stateInfo = "STOPPED";
break;
default:
break;
}
return stateInfo;
}
int32_t MuxerEngineImpl::TranslatePluginStatus(Plugin::Status error)
{
const static std::map<Plugin::Status, int32_t> g_transTable = {
{Plugin::Status::END_OF_STREAM, AVCodecServiceErrCode::AVCS_ERR_OK},
{Plugin::Status::OK, AVCodecServiceErrCode::AVCS_ERR_OK},
{Plugin::Status::NO_ERROR, AVCodecServiceErrCode::AVCS_ERR_OK},
{Plugin::Status::ERROR_UNKNOWN, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN},
{Plugin::Status::ERROR_PLUGIN_ALREADY_EXISTS, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN},
{Plugin::Status::ERROR_INCOMPATIBLE_VERSION, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN},
{Plugin::Status::ERROR_NO_MEMORY, AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY},
{Plugin::Status::ERROR_WRONG_STATE, AVCodecServiceErrCode::AVCS_ERR_INVALID_OPERATION},
{Plugin::Status::ERROR_UNIMPLEMENTED, AVCodecServiceErrCode::AVCS_ERR_UNSUPPORT},
{Plugin::Status::ERROR_INVALID_PARAMETER, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL},
{Plugin::Status::ERROR_INVALID_DATA, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL},
{Plugin::Status::ERROR_MISMATCHED_TYPE, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL},
{Plugin::Status::ERROR_TIMED_OUT, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN},
{Plugin::Status::ERROR_UNSUPPORTED_FORMAT, AVCodecServiceErrCode::AVCS_ERR_UNSUPPORT_CONTAINER_TYPE},
{Plugin::Status::ERROR_NOT_ENOUGH_DATA, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN},
{Plugin::Status::ERROR_NOT_EXISTED, AVCodecServiceErrCode::AVCS_ERR_OPEN_FILE_FAILED},
{Plugin::Status::ERROR_AGAIN, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN},
{Plugin::Status::ERROR_PERMISSION_DENIED, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN},
{Plugin::Status::ERROR_NULL_POINTER, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL},
{Plugin::Status::ERROR_INVALID_OPERATION, AVCodecServiceErrCode::AVCS_ERR_INVALID_OPERATION},
{Plugin::Status::ERROR_CLIENT, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN},
{Plugin::Status::ERROR_SERVER, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN},
{Plugin::Status::ERROR_DELAY_READY, AVCodecServiceErrCode::AVCS_ERR_OK},
};
auto ite = g_transTable.find(error);
if (ite == g_transTable.end()) {
return AVCS_ERR_UNKNOWN;
}
return ite->second;
}
} // Media
} // OHOS

View File

@ -0,0 +1,79 @@
/*
* 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.
*/
#ifndef MUXER_ENGINE_IMPL_H
#define MUXER_ENGINE_IMPL_H
#include <map>
#include <atomic>
#include <thread>
#include <mutex>
#include <condition_variable>
#include "i_muxer_engine.h"
#include "muxer.h"
#include "block_queue.h"
namespace OHOS {
namespace Media {
class MuxerEngineImpl : public IMuxerEngine {
public:
MuxerEngineImpl(int32_t appUid, int32_t appPid, int32_t fd, OutputFormat format);
~MuxerEngineImpl() override;
int32_t SetLocation(float latitude, float longitude) override;
int32_t SetRotation(int32_t rotation) override;
int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override;
int32_t Start() override;
int32_t WriteSampleBuffer(std::shared_ptr<AVSharedMemory> sampleBuffer, const TrackSampleInfo &info) override;
int32_t Stop() override;
int32_t DumpInfo(int32_t fd) override;
private:
int32_t StartThread(std::string name);
int32_t StopThread() noexcept;
void ThreadProcessor();
bool CanAddTrack(std::string &mimeType);
bool CheckKeys(std::string &mimeType, const MediaDescription &trackDesc);
std::string ConvertStateToString(int32_t state);
int32_t TranslatePluginStatus(Plugin::Status error);
private:
enum State {
UNINITIALIZED,
INITIALIZED,
STARTED,
STOPPED
};
struct BlockBuffer {
std::shared_ptr<AVSharedMemory> buffer_;
TrackSampleInfo info_;
};
int32_t appUid_ = -1;
int32_t appPid_ = -1;
int64_t fd_ = -1;
OutputFormat format_;
std::atomic<State> state_ = UNINITIALIZED;
std::shared_ptr<Plugin::Muxer> muxer_ = nullptr;
std::map<int32_t, std::string> tracks_;
BlockQueue<std::shared_ptr<BlockBuffer>> que_;
std::string threadName_;
std::mutex mutex_;
std::condition_variable cond_;
std::unique_ptr<std::thread> thread_ = nullptr;
bool isThreadExit_ = true;
};
} // namespace Media
} // namespace OHOS
#endif // MUXER_ENGINE_IMPL_H

View File

@ -10,15 +10,35 @@
# 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.
#
import("//build/ohos.gni")
import("//foundation/multimedia/av_codec/config.gni")
config("plugin_presets") {
include_dirs = [
"//foundation/multimedia/av_codec/interfaces/kits/c",
"//foundation/multimedia/av_codec/interfaces/inner_api/native",
"//foundation/multimedia/av_codec/services/dfx/include",
"//foundation/multimedia/av_codec/services/utils/include",
"//foundation/multimedia/av_codec/services/engine/plugin/core",
"//foundation/multimedia/av_codec/services/engine/plugin/interface",
"//third_party/bounds_checking_function/include",
"//base/hiviewdfx/hilog/interfaces/native/innerkits/include",
]
group("av_codec_engine_plugins") {
deps = []
if (multimedia_av_codec_support_demuxer) {
deps += [
#"plugins/demuxer:av_codec_engine_demuxer",
]
}
cflags = [
"-O2",
"-fPIC",
"-Wall",
"-frtti",
"-fexceptions",
]
cflags_cc = cflags
}
group("av_codec_plugin") {
deps = [
"plugins:av_codec_plugin_store",
]
}

View File

@ -0,0 +1,55 @@
/*
* 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 "muxer.h"
namespace OHOS {
namespace Media {
namespace Plugin {
Muxer::Muxer (uint32_t pkgVer, uint32_t apiVer, std::shared_ptr<MuxerPlugin> plugin)
: pkgVersion_(pkgVer), apiVersion_(apiVer), muxer_(std::move(plugin)) {}
Status Muxer::SetLocation(float latitude, float longitude)
{
return muxer_->SetLocation(latitude, longitude);
}
Status Muxer::SetRotation(int32_t rotation)
{
return muxer_->SetRotation(rotation);
}
Status Muxer::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc)
{
return muxer_->AddTrack(trackIndex, trackDesc);
}
Status Muxer::Start()
{
return muxer_->Start();
}
Status Muxer::WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info)
{
return muxer_->WriteSampleBuffer(sampleBuffer, info);
}
Status Muxer::Stop()
{
return muxer_->Stop();
}
} // namespace Plugin
} // namespace Media
} // namespace OHOS

View File

@ -0,0 +1,50 @@
/*
* 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.
*/
#ifndef PLUGIN_CORE_MUXER_H
#define PLUGIN_CORE_MUXER_H
#include "muxer_plugin.h"
namespace OHOS {
namespace Media {
namespace Plugin {
class Muxer {
public:
Muxer(const Muxer &) = delete;
Muxer operator=(const Muxer &) = delete;
~Muxer() = default;
Status SetLocation(float latitude, float longitude);
Status SetRotation(int32_t rotation);
Status AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc);
Status Start();
Status WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info);
Status Stop();
private:
friend class MuxerFactory;
Muxer(uint32_t pkgVer, uint32_t apiVer, std::shared_ptr<MuxerPlugin> plugin);
private:
const uint32_t pkgVersion_;
const uint32_t apiVersion_;
std::shared_ptr<MuxerPlugin> muxer_;
};
} // namespace Plugin
} // namespace Media
} // namespace OHOS
#endif // PLUGIN_CORE_MUXER_H

View File

@ -0,0 +1,173 @@
/*
* 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 "muxer_factory.h"
#include <utility>
#include <algorithm>
#include <dirent.h>
#include "muxer_plugin.h"
#include "avcodec_log.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MuxerFactory"};
}
namespace OHOS {
namespace Media {
namespace Plugin {
static std::string g_libFileHead = "libav_codec_plugin_";
static std::string g_fileSeparator = "/";
static std::string g_fileMark = "Muxer";
static std::string g_libFileTail = AV_CODEC_PLUGIN_FILE_TAIL;
MuxerFactory::MuxerFactory()
{
RegisterPlugins();
}
MuxerFactory::~MuxerFactory()
{
UnregisterAllPlugins();
}
std::shared_ptr<Muxer> MuxerFactory::CreatePlugin(int32_t fd, uint32_t outputFormat)
{
AVCODEC_LOGD("CreatePlugin: fd %{public}d, outputFormat %{public}d", fd, outputFormat);
std::string pluginName;
int32_t maxProb = 0;
for (auto& name : registerData_->registerNames) {
std::shared_ptr<PluginRegInfo> regInfo = registerData_->registerTable[name];
if (regInfo->pluginDef->pluginType == PluginType::MUXER) {
auto prob = regInfo->pluginDef->sniffer(name, outputFormat);
if (prob > maxProb) {
maxProb = prob;
pluginName = name;
}
}
}
AVCODEC_LOGD("maxProb %{public}d, pluginName %{public}s", maxProb, pluginName.c_str());
if (!pluginName.empty()) {
std::shared_ptr<PluginRegInfo> regInfo = registerData_->registerTable[pluginName];
auto plugin = regInfo->pluginDef->creator(pluginName, fd);
return std::shared_ptr<Muxer>(
new Muxer(regInfo->packageDef->pkgVersion, regInfo->pluginDef->apiVersion, plugin));
} else {
AVCODEC_LOGE("No plugins matching output format - %{public}d", outputFormat);
}
return nullptr;
}
void MuxerFactory::RegisterPlugins()
{
RegisterDynamicPlugins(AV_CODEC_PLUGIN_PATH);
}
void MuxerFactory::RegisterDynamicPlugins(const char* libDirPath)
{
DIR* libDir = opendir(libDirPath);
if (libDir) {
struct dirent* lib = nullptr;
std::shared_ptr<PluginLoader> loader = nullptr;
while ((lib = readdir(libDir))) {
if (lib->d_name[0] == '.') {
continue;
}
std::string libName = lib->d_name;
AVCODEC_LOGD("libName %{public}s", libName.c_str());
if (libName.find(g_libFileHead) ||
libName.find(g_fileMark) == std::string::npos ||
libName.compare(libName.size() - g_libFileTail.size(), g_libFileTail.size(), g_libFileTail)) {
continue;
}
std::string pluginName =
libName.substr(g_libFileHead.size(), libName.size() - g_libFileHead.size() - g_libFileTail.size());
std::string libPath = libDirPath + g_fileSeparator + lib->d_name;
loader = PluginLoader::Create(pluginName, libPath);
if (loader) {
loader->FetchRegisterFunction()(std::make_shared<RegisterImpl>(registerData_, loader));
registeredLoaders_.push_back(loader);
}
}
closedir(libDir);
}
}
void MuxerFactory::UnregisterAllPlugins()
{
for (auto& loader : registeredLoaders_) {
loader->FetchUnregisterFunction()();
loader.reset();
}
registeredLoaders_.clear();
registerData_->registerNames.clear();
registerData_->registerTable.clear();
}
bool MuxerFactory::RegisterData::IsExist(const std::string& name)
{
return registerTable.find(name) != registerTable.end();
}
Status MuxerFactory::RegisterImpl::AddPlugin(const PluginDefBase& def)
{
CHECK_AND_RETURN_RET_LOG(Verification(def), Status::ERROR_INVALID_DATA,
"The plugin type is not muxer, or plugin rank < 0, or plugin rank > 100");
CHECK_AND_RETURN_RET_LOG(VersionMatched(def), Status::ERROR_UNKNOWN,
"The plugin version is not matched");
CHECK_AND_RETURN_RET_LOG(!registerData->IsExist(def.name),
Status::ERROR_PLUGIN_ALREADY_EXISTS, "The plugin already exists");
auto& pluginDef = (MuxerPluginDef&)(def);
std::shared_ptr<PluginRegInfo> regInfo = std::make_shared<PluginRegInfo>();
regInfo->packageDef = packageDef;
regInfo->pluginDef = std::make_shared<MuxerPluginDef>(pluginDef);
regInfo->loader = std::move(pluginLoader);
registerData->registerTable[pluginDef.name] = regInfo;
registerData->registerNames.push_back(pluginDef.name);
return Status::NO_ERROR;
}
Status MuxerFactory::RegisterImpl::AddPackage(const PackageDef& def)
{
return SetPackageDef(def);
}
Status MuxerFactory::RegisterImpl::SetPackageDef(const PackageDef& def)
{
packageDef = std::make_shared<PackageDef>(def);
return Status::NO_ERROR;
}
bool MuxerFactory::RegisterImpl::Verification(const PluginDefBase& def)
{
if (def.rank < 0 || def.rank > 100) { // 100
return false;
}
return (def.pluginType == PluginType::MUXER);
}
bool MuxerFactory::RegisterImpl::VersionMatched(const PluginDefBase& def)
{
int major = (def.apiVersion >> 16) & 0xFFFF; // 16
int minor = def.apiVersion & 0xFFFF;
uint32_t version = MUXER_API_VERSION;
int coreMajor = (version >> 16) & 0xFFFF; // 16
int coreMinor = version & 0xFFFF;
return (major == coreMajor) && (minor <= coreMinor);
}
} // namespace Plugin
} // namespace Media
} // namespace OHOS

View File

@ -0,0 +1,81 @@
/*
* 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.
*/
#ifndef MUXER_FACTORY_H
#define MUXER_FACTORY_H
#include "muxer.h"
#include "plugin_loader.h"
#include <map>
#include <vector>
namespace OHOS {
namespace Media {
namespace Plugin {
class MuxerFactory {
public:
MuxerFactory(const MuxerFactory&) = delete;
MuxerFactory operator=(const MuxerFactory&) = delete;
~MuxerFactory();
static MuxerFactory& Instance()
{
static MuxerFactory impl;
return impl;
}
std::shared_ptr<Muxer> CreatePlugin(int32_t fd, uint32_t outputFormat);
private:
MuxerFactory();
void RegisterPlugins();
void RegisterDynamicPlugins(const char* libDirPath);
void UnregisterAllPlugins();
private:
struct PluginRegInfo {
std::shared_ptr<PackageDef> packageDef;
std::shared_ptr<MuxerPluginDef> pluginDef;
std::shared_ptr<PluginLoader> loader;
};
struct RegisterData {
std::vector<std::string> registerNames;
std::map<std::string, std::shared_ptr<PluginRegInfo>> registerTable;
bool IsExist(const std::string& name);
};
struct RegisterImpl : PackageRegister {
explicit RegisterImpl(std::shared_ptr<RegisterData> data, std::shared_ptr<PluginLoader> loader = nullptr)
: pluginLoader(std::move(loader)), registerData(std::move(data)) {}
~RegisterImpl() override = default;
Status AddPlugin(const PluginDefBase& def) override;
Status AddPackage(const PackageDef& def) override;
Status SetPackageDef(const PackageDef& def);
bool Verification(const PluginDefBase& def);
bool VersionMatched(const PluginDefBase& def);
std::shared_ptr<PluginLoader> pluginLoader;
std::shared_ptr<RegisterData> registerData;
std::shared_ptr<PackageDef> packageDef {nullptr};
};
std::shared_ptr<RegisterData> registerData_ = std::make_shared<RegisterData>();
std::vector<std::shared_ptr<PluginLoader>> registeredLoaders_;
};
} // namespace Plugin
} // namespace Media
} // namespace OHOS
#endif // MUXER_FACTORY_H

View File

@ -0,0 +1,93 @@
/*
* 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 "plugin_loader.h"
#include <dlfcn.h>
#include "avcodec_log.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "PluginLoader"};
}
using namespace OHOS::Media::Plugin;
// NOLINTNEXTLINE: void*
PluginLoader::PluginLoader(void* handler, std::string name) : handler_(handler), name_(std::move(name))
{
}
PluginLoader::~PluginLoader()
{
UnLoadPluginFile();
}
std::shared_ptr<PluginLoader> PluginLoader::Create(const std::string& name, const std::string& path)
{
if (name.empty() || path.empty()) {
return {};
}
return CheckSymbol(LoadPluginFile(path), name);
}
RegisterFunc PluginLoader::FetchRegisterFunction()
{
return registerFunc_;
}
UnregisterFunc PluginLoader::FetchUnregisterFunction()
{
return unregisterFunc_;
}
void* PluginLoader::LoadPluginFile(const std::string& path)
{
auto pathStr = path.c_str();
if (pathStr) {
auto ptr = ::dlopen(pathStr, RTLD_NOW | RTLD_LOCAL);
if (ptr == nullptr) {
AVCODEC_LOGE("dlopen failed due to %{public}s", ::dlerror());
}
return ptr;
}
return nullptr;
}
std::shared_ptr<PluginLoader> PluginLoader::CheckSymbol(void* handler, const std::string& name)
{
if (handler) {
std::string registerFuncName = "register_" + name;
std::string unregisterFuncName = "unregister_" + name;
RegisterFunc registerFunc = nullptr;
UnregisterFunc unregisterFunc = nullptr;
AVCODEC_LOGD("CheckSymbol: registerFuncName %{public}s", registerFuncName.c_str());
AVCODEC_LOGD("CheckSymbol: unregisterFuncName %{public}s", unregisterFuncName.c_str());
registerFunc = (RegisterFunc)(::dlsym(handler, registerFuncName.c_str()));
unregisterFunc = (UnregisterFunc)(::dlsym(handler, unregisterFuncName.c_str()));
if (registerFunc && unregisterFunc) {
std::shared_ptr<PluginLoader> loader(new PluginLoader(handler, name));
loader->registerFunc_ = registerFunc;
loader->unregisterFunc_ = unregisterFunc;
return loader;
}
}
return {};
}
void PluginLoader::UnLoadPluginFile()
{
if (handler_) {
::dlclose(const_cast<void*>(handler_)); // NOLINT: const_cast
}
}

View File

@ -0,0 +1,57 @@
/*
* 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.
*/
#ifndef PLUGIN_CORE_PLUGIN_LOADER_H
#define PLUGIN_CORE_PLUGIN_LOADER_H
#include "plugin_base.h"
#include "plugin_definition.h"
namespace OHOS {
namespace Media {
namespace Plugin {
class PluginLoader {
public:
PluginLoader(const PluginLoader &) = delete;
PluginLoader operator=(const PluginLoader &) = delete;
~PluginLoader();
static std::shared_ptr<PluginLoader> Create(const std::string &name, const std::string &path);
RegisterFunc FetchRegisterFunction();
UnregisterFunc FetchUnregisterFunction();
private:
PluginLoader(void* handler, std::string name); // NOLINT: void*
static void* LoadPluginFile(const std::string &path);
static std::shared_ptr<PluginLoader> CheckSymbol(void* handler, const std::string &name); // NOLINT: void*
void UnLoadPluginFile();
private:
const void *handler_;
const std::string name_;
RegisterFunc registerFunc_ {nullptr};
UnregisterFunc unregisterFunc_ {nullptr};
};
} // namespace Plugin
} // namespace Media
} // namespace OHOS
#endif // PLUGIN_CORE_PLUGIN_LOADER_H

View File

@ -0,0 +1,64 @@
/*
* 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.
*/
#ifndef PLUGIN_INTF_MUXER_PLUGIN_H
#define PLUGIN_INTF_MUXER_PLUGIN_H
#include "media_description.h"
#include "av_common.h"
#include "plugin_base.h"
#include "plugin_definition.h"
namespace OHOS {
namespace Media {
namespace Plugin {
struct MuxerPlugin : public PluginBase {
explicit MuxerPlugin(std::string &&name) : PluginBase(std::move(name)) {}
virtual Status SetLocation(float latitude, float longitude) = 0;
virtual Status SetRotation(int32_t rotation) = 0;
virtual Status AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) = 0;
virtual Status Start() = 0;
virtual Status WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info) = 0;
virtual Status Stop() = 0;
};
/// Muxer plugin api major number.
#define MUXER_API_VERSION_MAJOR (1)
/// Muxer plugin api minor number
#define MUXER_API_VERSION_MINOR (0)
/// Muxer plugin version
#define MUXER_API_VERSION MAKE_VERSION(MUXER_API_VERSION_MAJOR, MUXER_API_VERSION_MINOR)
/// Muxer create function
using MuxerPluginCreatorFunc = std::shared_ptr<MuxerPlugin>(*)(const std::string& name, int32_t fd);
/// Muxer sniff function
using MuxerPluginSnifferFunc = int32_t (*)(const std::string& name, uint32_t outputFormat);
struct MuxerPluginDef : public PluginDefBase {
MuxerPluginCreatorFunc creator {nullptr}; ///< Muxer plugin create function.
MuxerPluginSnifferFunc sniffer {nullptr}; ///< Muxer plugin sniff function.
MuxerPluginDef()
{
apiVersion = MUXER_API_VERSION; ///< Muxer plugin version.
pluginType = PluginType::MUXER; ///< Plugin type, MUST be MUXER.
}
};
} // Plugin
} // Media
} // OHOS
#endif // PLUGIN_INTF_MUXER_PLUGIN_H

View File

@ -0,0 +1,59 @@
/*
* 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.
*/
#ifndef PLUGIN_INTF_PLUGIN_BASE_H
#define PLUGIN_INTF_PLUGIN_BASE_H
#include <memory>
#include <string>
namespace OHOS {
namespace Media {
namespace Plugin {
/**
* @brief Base class of a plugin. All plugins of different types inherit this interface.
*
* @details The base class contains only common operation methods and defines basic operation processes.
* Different operations are valid only in the corresponding states. The timing of calls is guaranteed by
* the plugin framework. Some operations also change the plugin status.
* For details, see the description of each function.
*
* @since 10
* @version 1.0
*/
struct PluginBase {
/// Constructor
explicit PluginBase(std::string name): pluginName_(std::move(name)) {}
/// Destructor
virtual ~PluginBase() = default;
/**
* @brief Get plugin name
*
* @return plugin name
*/
std::string GetName() const
{
return pluginName_;
}
protected:
const std::string pluginName_;
};
} // namespace Plugin
} // namespace Media
} // namespace OHOS
#endif // PLUGIN_INTF_PLUGIN_BASE_H

View File

@ -0,0 +1,246 @@
/*
* 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.
*/
#ifndef PLUGIN_INTF_PLUGIN_DEFINITION_H
#define PLUGIN_INTF_PLUGIN_DEFINITION_H
#include <string>
#include <memory>
#include <cstdint> // NOLINT: using int32_t in this file
namespace OHOS {
namespace Media {
namespace Plugin {
/**
* @brief Macro definition, creating the version information.
*
* @details The versioning is the process of assigning a unique version number to a unique state
* of plugin interface. Within a given version number category (major, minor), these numbers are
* usually assigned in ascending order and correspond to new developments in the plugin.
*
* Given a version number MAJOR.MINOR:
* - MAJOR: When you make incompatible API changes.
* - MINOR: When you add features in a backwards-compatible manner or do backwards-compatible bug fixes.
*/
#define MAKE_VERSION(MAJOR, MINOR) ((((MAJOR)&0xFFFF) << 16) | ((MINOR)&0xFFFF))
/// Plugin interface major number
#define PLUGIN_INTERFACE_VERSION_MAJOR (1)
/// Plugin interface minor number
#define PLUGIN_INTERFACE_VERSION_MINOR (0)
/// Plugin interface version
#define PLUGIN_INTERFACE_VERSION MAKE_VERSION(PLUGIN_INTERFACE_VERSION_MAJOR, PLUGIN_INTERFACE_VERSION_MINOR)
/**
* @enum License Type.
* an official permission or permit.
*
* @since 10
* @version 1.0
*/
enum struct LicenseType : uint8_t {
APACHE_V2, ///< The Apache License 2.0
LGPL, ///< The GNU Lesser General Public License
GPL, ///< The GNU General Public License
CC0, ///< The Creative Commons Zero v1.0 Universal
UNKNOWN, ///< Unknown License
};
/**
* @brief Definition of plugin packaging information.
*
* @since 10
* @version 1.0
*/
struct PackageDef {
uint32_t pkgVersion; ///< Package information version, which indicates the latest plug-in interface version
///< used by the plugin in the package. The default value is PLUGIN_INTERFACE_VERSION.
std::string name; ///< Package name. The plugin framework registers the plugin using this name.
///< If the plugins are packaged as a dynamic library, the name of library
///< must be in the format of "libplugin_<name>.so".
LicenseType
licenseType; ///< The License information of the plugin in the package.
///< The different plugins must be the same.
///< The plugin framework processing in the plugin running state based on different license.
};
/**
* @enum Plugin Return Status.
*
* @since 10
* @version 1.0
*/
enum struct Status : int32_t {
END_OF_STREAM = 1, ///< Read source when end of stream
OK = 0, ///< The execution result is correct.
NO_ERROR = OK, ///< Same as Status::OK
ERROR_UNKNOWN = -1, ///< An unknown error occurred.
ERROR_PLUGIN_ALREADY_EXISTS = -2, ///< The plugin already exists, usually occurs when in plugin registered.
ERROR_INCOMPATIBLE_VERSION = -3, ///< Incompatible version, may occur during plugin registration or function calling.
ERROR_NO_MEMORY = -4, ///< The system memory is insufficient.
ERROR_WRONG_STATE = -5, ///< The function is called in an invalid state.
ERROR_UNIMPLEMENTED = -6, ///< This method or interface is not implemented.
ERROR_INVALID_PARAMETER = -7, ///< The plugin does not support this parameter.
ERROR_INVALID_DATA = -8, ///< The value is not in the valid range.
ERROR_MISMATCHED_TYPE = -9, ///< Mismatched data type
ERROR_TIMED_OUT = -10, ///< Operation timeout.
ERROR_UNSUPPORTED_FORMAT = -11, ///< The plugin not support this format/name.
ERROR_NOT_ENOUGH_DATA = -12, ///< Not enough data when read from source.
ERROR_NOT_EXISTED = -13, ///< Source is not existed.
ERROR_AGAIN = -14, ///< Operation is not available right now, should try again later.
ERROR_PERMISSION_DENIED = -15, ///< Permission denied.
ERROR_NULL_POINTER = -16, ///< Null pointer.
ERROR_INVALID_OPERATION = -17, ///< Invalid operation.
ERROR_CLIENT = -18, ///< Http client error
ERROR_SERVER = -19, ///< Http server error
ERROR_DELAY_READY = -20, ///< Delay ready event
};
/**
* @enum Plugin Type.
*
* @since 10
* @version 1.0
*/
enum struct PluginType : int32_t {
INVALID_TYPE = -1, ///< Invalid plugin
MUXER = 1, ///< reference MuxerPlugin
DEMUXER, ///< reference DemuxerPlugin
};
/**
* @brief Describes the basic information about the plugin.
*
* @since 10
* @version 1.0
*/
struct PluginDefBase {
uint32_t apiVersion; ///< Versions of different plugins. Different types of plugin have their own versions.
PluginType pluginType = PluginType::INVALID_TYPE; ///< Describe the plugin type, e.g. 'source', 'codec'.
std::string name; ///< Indicates the name of a plugin. The name of the same type plugins must be unique.
///< Plugins with the same name may fail to be registered.
std::string description; ///< Detailed description of the plugin.
uint32_t rank; ///< Plugin score. The plugin with a high score may be preferred. You can evaluate the
///< plugin score in terms of performance, version support, and license. Range: 0 to 100.
};
/**
* @brief The plugin registration interface.
* The plugin framework will provide the implementation.
* Developers only need to invoke the API to register the plugin.
*
* @since 10
* @version 1.0
*/
struct Register {
virtual ~Register() = default;
/**
* @brief Register the plugin.
*
* @param def Basic information about the plugin
* @return Registration status return
* @retval OK: The plugin is registered succeed.
* @retval ERROR_PLUGIN_ALREADY_EXISTS: The plugin already exists in plugin registered.
* @retval ERROR_INCOMPATIBLE_VERSION: Incompatible version during plugin registration.
*/
virtual Status AddPlugin(const PluginDefBase& def) = 0;
};
/**
* @brief The package registration interface.
* The plugin framework will provide the implementation and auto invoke the API to
* finish the package registration when plugin framework first time be initialized.
*
* @since 10
* @version 1.0
*/
struct PackageRegister : Register {
~PackageRegister() override = default;
/**
* @brief Register the package.
* During package registration, all plugins in the package are automatically registered.
*
* @param def plugin packaging information.
* @return Registration status return
* @retval OK: The package is registered succeed without any errors.
* @retval ERROR_PLUGIN_ALREADY_EXISTS: The package or plugins already exists.
* @retval ERROR_INCOMPATIBLE_VERSION: Incompatible plugin interface version or api version.
*/
virtual Status AddPackage(const PackageDef& def) = 0;
};
/// Plugin registration function, all plugins must be implemented.
using RegisterFunc = Status (*)(std::shared_ptr<Register> reg);
/// Plugin deregister function, all plugins must be implemented.
using UnregisterFunc = void (*)();
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
#define PLUGIN_EXPORT extern "C" __declspec(dllexport)
#else
#if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
#define PLUGIN_EXPORT extern "C" __attribute__((visibility("default")))
#else
#define PLUGIN_EXPORT
#endif
#endif
/// Macro definition, string concatenation
#define PLUGIN_PASTE_ARGS(str1, str2) str1##str2
/// Macro definition, string concatenation
#define PLUGIN_PASTE(str1, str2) PLUGIN_PASTE_ARGS(str1, str2)
/// Macro definition, stringify
#define PLUGIN_STRINGIFY_ARG(str) #str
/// Macro definition, stringify
#define PLUGIN_STRINGIFY(str) PLUGIN_STRINGIFY_ARG(str)
/**
* @brief Macro definition, Defines basic plugin information.
* Which is invoked during plugin package registration. All plugin packages must be implemented.
*
* @param name Package name. For details, @see PackageDef::name
* @param license Package License, For details, @see PackageDef::licenseType
* @param registerFunc Plugin registration function, MUST NOT be NULL.
* @param unregisterFunc Plugin deregister functionMUST NOT be NULL.
*/
#define PLUGIN_DEFINITION(name, license, registerFunc, unregisterFunc) \
PLUGIN_EXPORT OHOS::Media::Plugin::Status PLUGIN_PASTE(register_, name)( \
const std::shared_ptr<OHOS::Media::Plugin::PackageRegister>& pkgReg) \
{ \
pkgReg->AddPackage({PLUGIN_INTERFACE_VERSION, PLUGIN_STRINGIFY(name), license}); \
std::shared_ptr<OHOS::Media::Plugin::Register> pluginReg = pkgReg; \
return registerFunc(pluginReg); \
} \
PLUGIN_EXPORT void PLUGIN_PASTE(unregister_, name)() \
{ \
unregisterFunc(); \
}
} // namespace Plugin
} // namespace Media
} // namespace OHOS
#endif // PLUGIN_INTF_PLUGIN_DEFINITION_H

View File

@ -0,0 +1,19 @@
# 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.
#
import("//foundation/multimedia/av_codec/config.gni")
group("av_codec_plugin_store") {
deps = []
deps += [ "muxer/ffmpeg_muxer:plugin_muxer_ffmpeg" ]
}

View File

@ -0,0 +1,47 @@
# 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.
#
import("//foundation/multimedia/av_codec/config.gni")
group("plugin_muxer_ffmpeg") {
deps = []
deps += [ ":av_codec_plugin_FFmpegMuxer" ]
}
# standard
import("//build/ohos.gni")
ohos_shared_library("av_codec_plugin_FFmpegMuxer") {
sources = [
"ffmpeg_muxer_plugin.cpp",
"ffmpeg_utils.cpp",
]
include_dirs = [
"//third_party/ffmpeg",
]
public_configs = [
"//foundation/multimedia/av_codec/services/engine/plugin:plugin_presets",
]
public_deps = [
"//third_party/bounds_checking_function:libsec_static",
"//foundation/multimedia/av_codec/services/utils:av_codec_format",
"//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog",
"//third_party/ffmpeg:libohosffmpeg",
]
relative_install_dir = "media/av_codec_plugins"
subsystem_name = "multimedia"
part_name = "multimedia_av_codec"
}

View File

@ -0,0 +1,418 @@
/*
* 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 "ffmpeg_muxer_plugin.h"
#include <functional>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include "securec.h"
#include "ffmpeg_utils.h"
#include "avcodec_log.h"
#include "avcodec_common.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "FfmpegMuxerPlugin"};
}
namespace {
using namespace OHOS::Media;
using namespace Plugin;
using namespace Ffmpeg;
std::map<std::string, std::shared_ptr<AVOutputFormat>> g_pluginOutputFmt;
std::map<std::string, uint32_t> g_supportedMuxer = {{"mp4", OUTPUT_FORMAT_MPEG_4}, {"ipod", OUTPUT_FORMAT_M4A}};
bool IsMuxerSupported(const char *name)
{
auto it = g_supportedMuxer.find(name);
if (it != g_supportedMuxer.end()) {
return true;
}
return false;
}
int32_t Sniff(const std::string& pluginName, uint32_t outputFormat)
{
if (pluginName.empty()) {
return 0;
}
auto plugin = g_pluginOutputFmt[pluginName];
int32_t confidence = 0;
auto it = g_supportedMuxer.find(plugin->name);
if (it != g_supportedMuxer.end() && it->second == outputFormat) {
confidence = 60;
}
return confidence;
}
Status RegisterMuxerPlugins(const std::shared_ptr<Register>& reg)
{
const AVOutputFormat *outputFormat = nullptr;
void *ite = nullptr;
while ((outputFormat = av_muxer_iterate(&ite))) {
if (!IsMuxerSupported(outputFormat->name)) {
continue;
}
if (outputFormat->long_name != nullptr) {
if (!strncmp(outputFormat->long_name, "raw ", 4)) { // 4
continue;
}
}
std::string pluginName = "ffmpegMux_" + std::string(outputFormat->name);
ReplaceDelimiter(".,|-<> ", '_', pluginName);
MuxerPluginDef def;
def.name = pluginName;
def.description = "ffmpeg muxer";
def.rank = 100; // 100
def.creator = [](const std::string& name, int32_t fd) -> std::shared_ptr<MuxerPlugin> {
return std::make_shared<FFmpegMuxerPlugin>(name, fd);
};
def.sniffer = Sniff;
if (reg->AddPlugin(def) != Status::NO_ERROR) {
continue;
}
g_pluginOutputFmt[pluginName] = std::shared_ptr<AVOutputFormat>(
const_cast<AVOutputFormat*>(outputFormat), [](AVOutputFormat *ptr) {}); // do not delete
}
return Status::NO_ERROR;
}
PLUGIN_DEFINITION(FFmpegMuxer, LicenseType::LGPL, RegisterMuxerPlugins, [] {g_pluginOutputFmt.clear();})
void ResetCodecParameter(AVCodecParameters *par)
{
av_freep(&par->extradata);
(void)memset_s(par, sizeof(*par), 0, sizeof(*par));
par->codec_type = AVMEDIA_TYPE_UNKNOWN;
par->codec_id = AV_CODEC_ID_NONE;
par->format = -1;
par->profile = FF_PROFILE_UNKNOWN;
par->level = FF_LEVEL_UNKNOWN;
par->field_order = AV_FIELD_UNKNOWN;
par->color_range = AVCOL_RANGE_UNSPECIFIED;
par->color_primaries = AVCOL_PRI_UNSPECIFIED;
par->color_trc = AVCOL_TRC_UNSPECIFIED;
par->color_space = AVCOL_SPC_UNSPECIFIED;
par->chroma_location = AVCHROMA_LOC_UNSPECIFIED;
par->sample_aspect_ratio = AVRational {0, 1};
}
}
namespace OHOS {
namespace Media {
namespace Plugin {
namespace Ffmpeg {
FFmpegMuxerPlugin::FFmpegMuxerPlugin(std::string name, int32_t fd) : MuxerPlugin(std::move(name)), fd_(dup(fd))
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
if ((fcntl(fd_, F_GETFL, 0) & O_RDWR) != O_RDWR) {
AVCODEC_LOGE("No permission to read and write fd");
}
if (lseek(fd_, 0, SEEK_SET) < 0) {
AVCODEC_LOGE("The fd is not seekable");
}
auto pkt = av_packet_alloc();
cachePacket_ = std::shared_ptr<AVPacket> (pkt, [] (AVPacket *packet) {av_packet_free(&packet);});
outputFormat_ = g_pluginOutputFmt[pluginName_];
auto fmt = avformat_alloc_context();
fmt->pb = InitAvIoCtx(fd_, 1);
fmt->oformat = outputFormat_.get();
fmt->flags = static_cast<uint32_t>(fmt->flags) | static_cast<uint32_t>(AVFMT_FLAG_CUSTOM_IO);
fmt->io_open = IoOpen;
fmt->io_close = IoClose;
formatContext_ = std::shared_ptr<AVFormatContext>(fmt, [](AVFormatContext *ptr) {
if (ptr) {
DeInitAvIoCtx(ptr->pb);
avformat_free_context(ptr);
}
});
}
FFmpegMuxerPlugin::~FFmpegMuxerPlugin()
{
AVCODEC_LOGD("Destory");
outputFormat_.reset();
cachePacket_.reset();
formatContext_.reset();
CloseFd();
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
}
Status FFmpegMuxerPlugin::SetLocation(float latitude, float longitude)
{
std::string location = std::to_string(longitude) + " ";
location += std::to_string(latitude) + " ";
location += std::to_string(0.0f);
av_dict_set(&formatContext_.get()->metadata, "location", location.c_str(), 0);
return Status::NO_ERROR;
}
Status FFmpegMuxerPlugin::SetRotation(int32_t rotation)
{
rotation_ = rotation;
return Status::NO_ERROR;
}
Status FFmpegMuxerPlugin::SetCodecParameterOfTrack(AVStream *stream, const MediaDescription &trackDesc)
{
bool ret = false;
uint8_t *extraData = nullptr;
size_t extraDataSize = 0;
std::string mimeType = {};
AVCodecID codeID = AV_CODEC_ID_NONE;
CHECK_AND_RETURN_RET_LOG(trackDesc.GetStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, mimeType),
Status::ERROR_MISMATCHED_TYPE, "get mimeType failed!"); // mime
AVCODEC_LOGD("mimeType is %{public}s", mimeType.c_str());
CHECK_AND_RETURN_RET_LOG(Mime2CodecId(mimeType, codeID), Status::ERROR_INVALID_DATA,
"this mimeType do not support! mimeType:%{public}s", mimeType.c_str());
AVCodecParameters *par = stream->codecpar;
par->codec_id = codeID;
if (!mimeType.compare(0, 5, "audio")) {
par->codec_type = AVMEDIA_TYPE_AUDIO; // type
ret = trackDesc.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, par->sample_rate); // sample rate
CHECK_AND_RETURN_RET_LOG(ret, Status::ERROR_MISMATCHED_TYPE, "get audio sample_rate failed!");
ret = trackDesc.GetIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, par->channels); // channels
CHECK_AND_RETURN_RET_LOG(ret, Status::ERROR_MISMATCHED_TYPE, "get audio channels failed!");
} else if(!mimeType.compare(0, 5, "video") || !mimeType.compare(0, 5, "image")) {
if (!mimeType.compare(0, 5, "image")) { // pic
stream->disposition = AV_DISPOSITION_ATTACHED_PIC;
}
par->codec_type = AVMEDIA_TYPE_VIDEO; // type
ret = trackDesc.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, par->width); // width
CHECK_AND_RETURN_RET_LOG(ret, Status::ERROR_MISMATCHED_TYPE, "get video width failed!");
ret = trackDesc.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, par->height); // height
CHECK_AND_RETURN_RET_LOG(ret, Status::ERROR_MISMATCHED_TYPE, "get video height failed!");
} else{
AVCODEC_LOGD("mimeType %{public}s is unsupported", mimeType.c_str());
}
trackDesc.GetLongValue(MediaDescriptionKey::MD_KEY_BITRATE, par->bit_rate); // bit rate
if (trackDesc.GetBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, &extraData, extraDataSize)) { // codec config
par->extradata = static_cast<uint8_t *>(av_mallocz(extraDataSize + AV_INPUT_BUFFER_PADDING_SIZE));
CHECK_AND_RETURN_RET_LOG(par->extradata != nullptr, Status::ERROR_NO_MEMORY, "codec config malloc failed!");
par->extradata_size = static_cast<int32_t>(extraDataSize);
errno_t rc = memcpy_s(par->extradata, par->extradata_size, extraData, extraDataSize);
CHECK_AND_RETURN_RET_LOG(rc == EOK, Status::ERROR_UNKNOWN, "memcpy_s failed");
}
return Status::NO_ERROR;
}
Status FFmpegMuxerPlugin::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc)
{
CHECK_AND_RETURN_RET_LOG(outputFormat_ != nullptr, Status::ERROR_NULL_POINTER, "AVOutputFormat is nullptr");
auto st = avformat_new_stream(formatContext_.get(), nullptr);
CHECK_AND_RETURN_RET_LOG(st != nullptr, Status::ERROR_NO_MEMORY, "avformat_new_stream failed!");
st->codecpar->codec_type = AVMEDIA_TYPE_UNKNOWN;
st->codecpar->codec_id = AV_CODEC_ID_NONE;
trackIndex = st->index;
// 设置track参数
ResetCodecParameter(st->codecpar);
Status ret = SetCodecParameterOfTrack(st, trackDesc);
CHECK_AND_RETURN_RET_LOG(ret == Status::NO_ERROR, ret, "SetCodecParameter failed!");
formatContext_->flags |= AVFMT_TS_NONSTRICT;
return Status::NO_ERROR;
}
Status FFmpegMuxerPlugin::Start()
{
if (rotation_ != 0) {
std::string rotate = std::to_string(rotation_);
for (uint32_t i = 0; i < formatContext_->nb_streams; i++) {
if (formatContext_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
av_dict_set(&formatContext_->streams[i]->metadata, "rotate", rotate.c_str(), 0);
}
}
}
AVDictionary *options = nullptr;
av_dict_set(&options, "movflags", "faststart", 0);
int ret = avformat_write_header(formatContext_.get(), &options);
if (ret < 0) {
AVCODEC_LOGE("write header failed, %{public}s", AVStrError(ret).c_str());
return Status::ERROR_UNKNOWN;
}
return Status::NO_ERROR;
}
Status FFmpegMuxerPlugin::Stop()
{
int ret = av_write_frame(formatContext_.get(), nullptr); // flush out cache data
if (ret < 0) {
AVCODEC_LOGE("write trailer failed, %{public}s", AVStrError(ret).c_str());
}
ret = av_write_trailer(formatContext_.get());
if (ret != 0) {
AVCODEC_LOGE("write trailer failed, %{public}s", AVStrError(ret).c_str());
}
avio_flush(formatContext_->pb);
CloseFd();
return Status::NO_ERROR;
}
Status FFmpegMuxerPlugin::WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info)
{
CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, Status::ERROR_NULL_POINTER, "av_write_frame sampleBuffer is null!");
CHECK_AND_RETURN_RET_LOG(info.trackIndex < formatContext_->nb_streams, Status::ERROR_INVALID_PARAMETER, "track index is invalid!");
(void)memset_s(cachePacket_.get(), sizeof(AVPacket), 0, sizeof(AVPacket));
cachePacket_->data = sampleBuffer;
cachePacket_->size = info.size;
cachePacket_->stream_index = static_cast<int>(info.trackIndex);
cachePacket_->pts = ConvertTimeToFFmpeg(info.timeUs, formatContext_->streams[info.trackIndex]->time_base);
cachePacket_->dts = cachePacket_->pts;
cachePacket_->flags = 0;
if (info.flags & AVCODEC_BUFFER_FLAG_SYNC_FRAME) {
AVCODEC_LOGD("It is key frame");
cachePacket_->flags |= AV_PKT_FLAG_KEY;
}
auto ret = av_write_frame(formatContext_.get(), cachePacket_.get());
av_packet_unref(cachePacket_.get());
if (ret < 0) {
AVCODEC_LOGE("write sample buffer failed, %{public}s", AVStrError(ret).c_str());
return Status::ERROR_UNKNOWN;
}
return Status::NO_ERROR;
}
AVIOContext *FFmpegMuxerPlugin::InitAvIoCtx(int32_t fd, int writeFlags)
{
IOContext *ioContext = new IOContext();
ioContext->fd_ = fd;
ioContext->pos_ = 0;
ioContext->end_ = 0;
constexpr int bufferSize = 4 * 1024; // 4096
auto buffer = static_cast<unsigned char*>(av_malloc(bufferSize));
AVIOContext *avioContext = avio_alloc_context(buffer, bufferSize, writeFlags, static_cast<void*>(ioContext),
IoRead, IoWrite, IoSeek);
if (avioContext == nullptr) {
delete ioContext;
av_free(buffer);
return nullptr;
}
avioContext->seekable = AVIO_SEEKABLE_NORMAL;
return avioContext;
}
void FFmpegMuxerPlugin::DeInitAvIoCtx(AVIOContext *ptr)
{
if (ptr != nullptr) {
delete static_cast<IOContext*>(ptr->opaque);
ptr->opaque = nullptr;
av_freep(&ptr->buffer);
av_opt_free(ptr);
avio_context_free(&ptr);
}
}
void FFmpegMuxerPlugin::CloseFd()
{
if (fd_ != -1) {
AVCODEC_LOGD("close fd");
close(fd_);
fd_ = -1;
}
}
int32_t FFmpegMuxerPlugin::IoRead(void *opaque, uint8_t *buf, int bufSize)
{
auto ioCtx = static_cast<IOContext*>(opaque);
if (ioCtx && ioCtx->fd_ != -1) {
int64_t ret = lseek(ioCtx->fd_, ioCtx->pos_, SEEK_SET);
if (ret != -1) {
ssize_t size = read(ioCtx->fd_, buf, bufSize);
if (size < 0) {
return -1;
}
ioCtx->pos_ += size;
if (ioCtx->pos_ > ioCtx->end_) {
ioCtx->end_ = ioCtx->pos_;
}
return size;
}
return 0;
}
return -1;
}
int32_t FFmpegMuxerPlugin::IoWrite(void *opaque, uint8_t *buf, int bufSize)
{
auto ioCtx = static_cast<IOContext*>(opaque);
if (ioCtx && ioCtx->fd_ != -1) {
int64_t ret = lseek(ioCtx->fd_, ioCtx->pos_, SEEK_SET);
if (ret != -1) {
ssize_t size = write(ioCtx->fd_, buf, bufSize);
if (size < 0) {
return -1;
}
ioCtx->pos_ += size;
if (ioCtx->pos_ > ioCtx->end_) {
ioCtx->end_ = ioCtx->pos_;
}
return size;
}
return 0;
}
return -1;
}
int64_t FFmpegMuxerPlugin::IoSeek(void *opaque, int64_t offset, int whence)
{
auto ioContext = static_cast<IOContext*>(opaque);
uint64_t newPos = 0;
switch (whence) {
case SEEK_SET:
newPos = static_cast<uint64_t>(offset);
ioContext->pos_ = newPos;
break;
case SEEK_CUR:
newPos = ioContext->pos_ + offset;
break;
case SEEK_END:
case AVSEEK_SIZE:
newPos = ioContext->end_ + offset;
break;
default:
break;
}
if (whence != AVSEEK_SIZE) {
ioContext->pos_ = newPos;
}
return newPos;
}
int32_t FFmpegMuxerPlugin::IoOpen(AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options)
{
AVCODEC_LOGD("IoOpen flags %{public}d", flags);
*pb = InitAvIoCtx(static_cast<IOContext*>(s->pb->opaque)->fd_, 0);
return 0;
}
void FFmpegMuxerPlugin::IoClose(AVFormatContext *s, AVIOContext *pb)
{
avio_flush(pb);
DeInitAvIoCtx(pb);
}
} // Ffmpeg
} // Plugin
} // Media
} // OHOS

View File

@ -0,0 +1,73 @@
/*
* 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.
*/
#ifndef FFMPEG_MUXER_PLUGIN_H
#define FFMPEG_MUXER_PLUGIN_H
#include "muxer_plugin.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "libavformat/avformat.h"
#include "libavutil/opt.h"
#ifdef __cplusplus
}
#endif
namespace OHOS {
namespace Media {
namespace Plugin {
namespace Ffmpeg {
class FFmpegMuxerPlugin : public MuxerPlugin {
public:
explicit FFmpegMuxerPlugin(std::string name, int32_t fd);
~FFmpegMuxerPlugin() override;
Status SetLocation(float latitude, float longitude) override;
Status SetRotation(int32_t rotation) override;
Status AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override;
Status Start() override;
Status WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info) override;
Status Stop() override;
private:
Status SetCodecParameterOfTrack(AVStream *stream, const MediaDescription &trackDesc);
static int32_t IoRead(void *opaque, uint8_t *buf, int bufSize);
static int32_t IoWrite(void *opaque, uint8_t *buf, int bufSize);
static int64_t IoSeek(void *opaque, int64_t offset, int whence);
static AVIOContext *InitAvIoCtx(int32_t fd, int writeFlags);
static void DeInitAvIoCtx(AVIOContext *ptr);
static int32_t IoOpen(AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options);
static void IoClose(AVFormatContext *s, AVIOContext *pb);
void CloseFd();
private:
struct IOContext {
int32_t fd_ {-1};
int64_t pos_ {0};
int64_t end_ {0};
};
int32_t fd_ {-1};
std::shared_ptr<AVPacket> cachePacket_ {};
std::shared_ptr<AVOutputFormat> outputFormat_ {};
std::shared_ptr<AVFormatContext> formatContext_ {};
int32_t rotation_ { 0 };
};
} // Ffmpeg
} // Plugin
} // Media
} // OHOS
#endif // FFMPEG_MUXER_PLUGIN_H

View File

@ -0,0 +1,129 @@
/*
* 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 "ffmpeg_utils.h"
#include <algorithm>
#include <functional>
#include <unordered_map>
#include "avcodec_info.h"
namespace OHOS {
namespace Media {
namespace Plugin {
namespace Ffmpeg {
// Internal definitions
namespace {
/* time scale microsecond */
constexpr int32_t TIME_SCALE_US = 1000000;
/* MIME to AVCodecID */
std::unordered_map<std::string_view, AVCodecID> g_mimeToCodecId = {
{CodecMimeType::AUDIO_MPEG, AV_CODEC_ID_MP3},
{CodecMimeType::AUDIO_FLAC, AV_CODEC_ID_FLAC},
{CodecMimeType::AUDIO_RAW, AV_CODEC_ID_PCM_S16LE},
{CodecMimeType::AUDIO_AAC, AV_CODEC_ID_AAC},
{CodecMimeType::AUDIO_VORBIS, AV_CODEC_ID_VORBIS},
{CodecMimeType::AUDIO_OPUS, AV_CODEC_ID_OPUS},
{CodecMimeType::AUDIO_AMR_NB, AV_CODEC_ID_AMR_NB},
{CodecMimeType::AUDIO_AMR_WB, AV_CODEC_ID_AMR_WB},
{CodecMimeType::VIDEO_AVC, AV_CODEC_ID_H264},
{CodecMimeType::VIDEO_MPEG4, AV_CODEC_ID_MPEG4},
{CodecMimeType::IMAGE_JPG, AV_CODEC_ID_MJPEG},
{CodecMimeType::IMAGE_PNG, AV_CODEC_ID_PNG},
{CodecMimeType::IMAGE_BMP, AV_CODEC_ID_BMP},
};
} // namespace
bool Mime2CodecId(const std::string_view &mime, AVCodecID &codecId)
{
auto it = g_mimeToCodecId.find(mime);
if (it != g_mimeToCodecId.end()) {
codecId = it->second;
return true;
}
return false;
}
void ReplaceDelimiter(const std::string &delmiters, char newDelimiter, std::string &str)
{
for (auto it = str.begin(); it != str.end(); ++it) {
if (delmiters.find(newDelimiter) != std::string::npos) {
*it = newDelimiter;
}
}
}
std::vector<std::string> SplitString(const char* str, char delimiter)
{
std::vector<std::string> rtv;
if (str) {
SplitString(std::string(str), delimiter).swap(rtv);
}
return rtv;
}
std::vector<std::string> SplitString(const std::string &str, char delimiter)
{
if (str.empty()) {
return {};
}
std::vector<std::string> rtv;
std::string::size_type startPos = 0;
std::string::size_type endPos = str.find_first_of(delimiter, startPos);
while (startPos != endPos) {
rtv.emplace_back(str.substr(startPos, endPos - startPos));
if (endPos == std::string::npos) {
break;
}
startPos = endPos + 1;
endPos = str.find_first_of(delimiter, startPos);
}
return rtv;
}
std::string AVStrError(int errnum)
{
char errbuf[AV_ERROR_MAX_STRING_SIZE] = {0};
av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
return std::string(errbuf);
}
int64_t ConvertTimeFromFFmpeg(int64_t pts, AVRational base)
{
int64_t out;
if (pts == AV_NOPTS_VALUE) {
out = -1;
} else {
AVRational bq = {1, TIME_SCALE_US};
out = av_rescale_q(pts, base, bq);
}
return out;
}
int64_t ConvertTimeToFFmpeg(int64_t timestampUs, AVRational base)
{
int64_t result;
if (base.num == 0) {
result = AV_NOPTS_VALUE;
} else {
AVRational bq = {1, TIME_SCALE_US};
result = av_rescale_q(timestampUs, bq, base);
}
return result;
}
} // namespace Ffmpeg
} // namespace Plugin
} // namespace Media
} // namespace OHOS

View File

@ -0,0 +1,71 @@
/*
* 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.
*/
#ifndef FFMPEG_UTILS_H
#define FFMPEG_UTILS_H
#include <string>
#include <type_traits>
#include <vector>
#ifdef __cplusplus
extern "C" {
#endif
#include "libavcodec/avcodec.h"
#include "libavutil/channel_layout.h"
#include "libavutil/error.h"
#include "libavutil/frame.h"
#include "libavutil/imgutils.h"
#include "libavutil/pixdesc.h"
#include "libavutil/pixfmt.h"
#include "libswresample/swresample.h"
#include "libswscale/swscale.h"
#ifdef __cplusplus
};
#endif
namespace OHOS {
namespace Media {
namespace Plugin {
namespace Ffmpeg {
bool Mime2CodecId(const std::string_view &mime, AVCodecID &codecId);
void ReplaceDelimiter(const std::string &delmiters, char newDelimiter, std::string &str);
std::vector<std::string> SplitString(const char* str, char delimiter);
std::vector<std::string> SplitString(const std::string &str, char delimiter);
std::string AVStrError(int errnum);
/**
* Convert time from ffmpeg to time in HST_TIME_BASE.
* @param pts ffmpeg time
* @param base ffmpeg time_base
* @return time in HST_TIME_BASE
*/
int64_t ConvertTimeFromFFmpeg(int64_t pts, AVRational base);
/**
* Convert time in TIME_BASE to ffmpeg time.
* @param time time in HST_TIME_BASE
* @param base ffmpeg time_base
* @return time in ffmpeg.
*/
int64_t ConvertTimeToFFmpeg(int64_t timestampUs, AVRational base);
} // namespace Ffmpeg
} // namespace Plugin
} // namespace Media
} // namespace OHOS
#endif // FFMPEG_UTILS_H

View File

@ -7,4 +7,4 @@
"secon" : "u:r:media_service:s0"
}
]
}
}

View File

@ -31,7 +31,7 @@
#endif
#ifdef SUPPORT_MUXER
#include "i_avmuxer.h"
#include "i_muxer_service.h"
#endif
#ifdef SUPPORT_SOURCE
@ -99,8 +99,28 @@ public:
#endif
#ifdef SUPPORT_MUXER
virtual std::shared_ptr<IAVMuxer> CreateMuxerService() = 0;
virtual int32_t DestroyMuxerService(std::shared_ptr<IAVMuxer> muxer) = 0;
/**
* @brief Create an muxer service.
*
* All muxer functions must be created and obtained first.
*
* @return Returns a valid pointer if the setting is successful;
* @since 10
* @version 4.0
*/
virtual std::shared_ptr<IMuxerService> CreateMuxerService() = 0;
/**
* @brief Destroy a muxer service.
*
* call the API to destroy the muxer service.
*
* @param pointer to the muxer service.
* @return Returns a valid pointer if the setting is successful;
* @since 10
* @version 4.0
*/
virtual int32_t DestroyMuxerService(std::shared_ptr<IMuxerService> muxer) = 0;
#endif
#ifdef SUPPORT_SOURCE
@ -114,7 +134,7 @@ public:
/**
* @brief IAVCodecService singleton
*
* Create Recorder Service and Player Service Through the Avcodec Service.
* Create Muxer and Demuxer Service Through the AVCodec Service.
*
* @return Returns IAVCodecService singleton;
* @since 4.0

View File

@ -1,28 +0,0 @@
#ifndef I_MUXER_SERVICE_H
#define I_MUXER_SERVICE_H
#include <string>
#include <memory>
#include "format.h"
#include "avcodec_common.h"
namespace OHOS {
namespace Media {
class IAVMuxer {
public:
virtual ~IAVMuxer() = default;
// 业务
virtual int32_t Init() = 0;
virtual int32_t SetLocation(float latitude, float longitude) = 0;
virtual int32_t SetRotation(int32_t rotation) = 0;
virtual int32_t SetParameter(const Format &generalFormat) = 0;
virtual int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) = 0;
virtual int32_t Start() = 0;
virtual int32_t WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr<AVSharedMemory> &sampleBuffer,
AVCodecBufferInfo info) = 0;
virtual int32_t Stop() = 0;
};
} // namespace Media
} // namespace OHOS
#endif // I_MUXER_SERVICE_H

View File

@ -0,0 +1,42 @@
/*
* 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.
*/
#ifndef I_MUXER_SERVICE_H
#define I_MUXER_SERVICE_H
#include <string>
#include <memory>
#include "avsharedmemory.h"
#include "media_description.h"
#include "av_common.h"
namespace OHOS {
namespace Media {
class IMuxerService {
public:
virtual ~IMuxerService() = default;
virtual int32_t InitParameter(int32_t fd, OutputFormat format) = 0;
virtual int32_t SetLocation(float latitude, float longitude) = 0;
virtual int32_t SetRotation(int32_t rotation) = 0;
virtual int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) = 0;
virtual int32_t Start() = 0;
virtual int32_t WriteSampleBuffer(std::shared_ptr<AVSharedMemory> sampleBuffer, const TrackSampleInfo &info) = 0;
virtual int32_t Stop() = 0;
virtual void Release() = 0;
};
} // namespace Media
} // namespace OHOS
#endif // I_MUXER_SERVICE_H

View File

@ -81,12 +81,16 @@ config("av_codec_service_config") {
"//foundation/multimedia/av_codec/services/dfx/include/",
"//foundation/multimedia/av_codec/services/engine/",
"//foundation/multimedia/av_codec/services/engine/avcodeclist",
"//foundation/multimedia/av_codec/services/engine/muxer",
"//foundation/multimedia/av_codec/services/engine/plugin/core",
"//foundation/multimedia/av_codec/services/engine/plugin/interface",
"//foundation/multimedia/av_codec/services/engine/plugin/",
"//foundation/multimedia/av_codec/services/engine/plugin/plugins/",
"//foundation/multimedia/av_codec/services/engine/plugin/plugins/demuxer/",
"//foundation/multimedia/av_codec/services/engine/plugin/plugins/demuxer/ffmpeg_demuxer/",
"//foundation/multimedia/av_codec/services/include/",
"//foundation/multimedia/av_codec/services/services/",
"//foundation/multimedia/av_codec/services/services/factory",
"//foundation/multimedia/av_codec/services/services/avcodeclist/",
"//foundation/multimedia/av_codec/services/services/avcodeclist/client",
"//foundation/multimedia/av_codec/services/services/avcodeclist/ipc",
@ -106,9 +110,9 @@ config("av_codec_service_config") {
"//foundation/multimedia/av_codec/services/services/demuxer/ipc/",
"//foundation/multimedia/av_codec/services/services/demuxer/server/",
"//foundation/multimedia/av_codec/services/services/muxer/",
"//foundation/multimedia/av_codec/services/services/muxer/client/include",
"//foundation/multimedia/av_codec/services/services/muxer/ipc/include",
"//foundation/multimedia/av_codec/services/services/muxer/server/include",
"//foundation/multimedia/av_codec/services/services/muxer/client",
"//foundation/multimedia/av_codec/services/services/muxer/ipc",
"//foundation/multimedia/av_codec/services/services/muxer/server",
"//foundation/multimedia/av_codec/services/services/sa_avcodec/",
"//foundation/multimedia/av_codec/services/services/sa_avcodec/client/",
"//foundation/multimedia/av_codec/services/services/sa_avcodec/ipc/",
@ -131,6 +135,17 @@ config("av_codec_service_config") {
if (target_cpu == "arm") {
cflags += [ "-DBINDER_IPC_32BIT" ]
}
if (target_cpu == "arm64") {
av_codec_plugin_path = "\"/system/lib64/media/av_codec_plugins\""
} else {
av_codec_plugin_path = "\"/system/lib/media/av_codec_plugins\""
}
defines += [
"AV_CODEC_PLUGIN_PATH=${av_codec_plugin_path}",
"AV_CODEC_PLUGIN_FILE_TAIL=\".z.so\"",
]
}
ohos_shared_library("av_codec_service") {
@ -155,6 +170,10 @@ ohos_shared_library("av_codec_service") {
"sa_avcodec/ipc/avcodec_service_stub.cpp",
"sa_avcodec/server/avcodec_server.cpp",
"sa_avcodec/server/avcodec_server_manager.cpp",
"//foundation/multimedia/av_codec/services/engine/muxer/muxer_engine_impl.cpp",
"//foundation/multimedia/av_codec/services/engine/plugin/core/muxer_factory.cpp",
"//foundation/multimedia/av_codec/services/engine/plugin/core/muxer.cpp",
"//foundation/multimedia/av_codec/services/engine/plugin/core/plugin_loader.cpp",
]
@ -174,8 +193,8 @@ ohos_shared_library("av_codec_service") {
}
if (multimedia_av_codec_support_muxer) {
sources += [
"muxer/ipc/avmuxer_stub.cpp",
"muxer/server/avmuxer_server.cpp",
"muxer/ipc/muxer_service_stub.cpp",
"muxer/server/muxer_server.cpp",
]
}
@ -184,6 +203,7 @@ ohos_shared_library("av_codec_service") {
"$AV_CODEC_ROOT_DIR/services/dfx:av_codec_service_dfx",
"$AV_CODEC_ROOT_DIR/services/utils:av_codec_format",
"$AV_CODEC_ROOT_DIR/services/utils:av_codec_service_utils",
"$AV_CODEC_ROOT_DIR/services/engine:av_codec_engine_package",
]
external_deps = [

View File

@ -0,0 +1,47 @@
/*
* 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.
*/
#ifndef IMUXER_ENGINE_H
#define IMUXER_ENGINE_H
#include <cstdint>
#include "avsharedmemory.h"
#include "media_description.h"
#include "av_common.h"
namespace OHOS {
namespace Media {
class IMuxerEngine {
public:
virtual ~IMuxerEngine() = default;
virtual int32_t SetLocation(float latitude, float longitude) = 0;
virtual int32_t SetRotation(int32_t rotation) = 0;
virtual int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) = 0;
virtual int32_t Start() = 0;
virtual int32_t WriteSampleBuffer(std::shared_ptr<AVSharedMemory> sampleBuffer, const TrackSampleInfo &info) = 0;
virtual int32_t Stop() = 0;
virtual int32_t DumpInfo(int32_t fd) = 0;
};
class __attribute__((visibility("default"))) IMuxerEngineFactory {
public:
static std::shared_ptr<IMuxerEngine> CreateMuxerEngine(int32_t appUid, int32_t appPid, int32_t fd, OutputFormat format);
private:
IMuxerEngineFactory() = default;
~IMuxerEngineFactory() = default;
};
} // namespace Media
} // namespace OHOS
#endif // IMUXER_ENGINE_H

View File

@ -13,31 +13,30 @@
* limitations under the License.
*/
#include <mutex>
#include "avmuxer_client.h"
#include "muxer_client.h"
#include "avcodec_errors.h"
#include "avcodec_log.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMuxerClient"};
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MuxerClient"};
}
namespace OHOS {
namespace Media {
std::shared_ptr<AVMuxerClient> AVMuxerClient::Create(const sptr<IAVMuxerService> &ipcProxy)
std::shared_ptr<MuxerClient> MuxerClient::Create(const sptr<IStandardMuxerService> &ipcProxy)
{
std::shared_ptr<AVMuxerClient> muxerClient = std::make_shared<AVMuxerClient>(ipcProxy);
CHECK_AND_RETURN_RET_LOG(muxerClient != nullptr, nullptr, "Failed to create muxer client");
std::shared_ptr<MuxerClient> muxerClient = std::make_shared<MuxerClient>(ipcProxy);
CHECK_AND_RETURN_RET_LOG(muxerClient != nullptr, nullptr, "Create muxer client failed");
return muxerClient;
}
AVMuxerClient::AVMuxerClient(const sptr<IAVMuxerService> &ipcProxy)
MuxerClient::MuxerClient(const sptr<IStandardMuxerService> &ipcProxy)
: muxerProxy_(ipcProxy)
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
}
AVMuxerClient::~AVMuxerClient()
MuxerClient::~MuxerClient()
{
std::lock_guard<std::mutex> lock(mutex_);
if (muxerProxy_ != nullptr) {
@ -47,67 +46,67 @@ AVMuxerClient::~AVMuxerClient()
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
}
void AVMuxerClient::AVCodecServerDied()
void MuxerClient::AVCodecServerDied()
{
std::lock_guard<std::mutex> lock(mutex_);
muxerProxy_ = nullptr;
}
int32_t AVMuxerClient::Init()
int32_t MuxerClient::InitParameter(int32_t fd, OutputFormat format)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerProxy_->Init();
return muxerProxy_->InitParameter(fd, format);
}
int32_t AVMuxerClient::SetLocation(float latitude, float longitude)
int32_t MuxerClient::SetLocation(float latitude, float longitude)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerProxy_->SetLocation(latitude, longitude);
}
int32_t AVMuxerClient::SetRotation(int32_t rotation)
int32_t MuxerClient::SetRotation(int32_t rotation)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerProxy_->SetRotation(rotation);
}
int32_t AVMuxerClient::SetParameter(const Format &generalFormat)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "codec service does not exist.");
return muxerProxy_->SetParameter(generalFormat);
}
int32_t AVMuxerClient::AddTrack(uint32_t &trackIndex, const Format &trackFormat)
int32_t MuxerClient::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerProxy_->AddTrack(trackIndex, trackFormat);
return muxerProxy_->AddTrack(trackIndex, trackDesc);
}
int32_t AVMuxerClient::Start()
int32_t MuxerClient::Start()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerProxy_->Start();
}
int32_t AVMuxerClient::WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr<AVSharedMemory> &sampleBuffer, AVCodecBufferInfo info)
int32_t MuxerClient::WriteSampleBuffer(std::shared_ptr<AVSharedMemory> sampleBuffer, const TrackSampleInfo &info)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, AVCS_ERR_INVALID_VAL, "SampleBuffer is nullptr");
CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, AVCS_ERR_INVALID_VAL, "sampleBuffer is nullptr");
CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerProxy_->WriteSampleBuffer(trackIndex, sampleBuffer, info);
return muxerProxy_->WriteSampleBuffer(sampleBuffer, info);
}
int32_t AVMuxerClient::Stop()
int32_t MuxerClient::Stop()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerProxy_->Stop();
}
void MuxerClient::Release()
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_LOG(muxerProxy_ != nullptr, "Muxer Service does not exist");
muxerProxy_->Release();
}
} // namespace Media
} // namespace OHOS

View File

@ -16,30 +16,31 @@
#ifndef MUXER_CLIENT_H
#define MUXER_CLIENT_H
#include "i_avmuxer.h"
#include "i_avmuxer_service.h"
#include <mutex>
#include "i_muxer_service.h"
#include "i_standard_muxer_service.h"
namespace OHOS {
namespace Media {
class AVMuxerClient : public IAVMuxer, public NoCopyable {
class MuxerClient : public IMuxerService, public NoCopyable {
public:
static std::shared_ptr<AVMuxerClient> Create(const sptr<IAVMuxerService> &ipcProxy);
explicit AVMuxerClient(const sptr<IAVMuxerService> &ipcProxy);
~AVMuxerClient();
static std::shared_ptr<MuxerClient> Create(const sptr<IStandardMuxerService> &ipcProxy);
explicit MuxerClient(const sptr<IStandardMuxerService> &ipcProxy);
~MuxerClient();
int32_t Init() override;
int32_t InitParameter(int32_t fd, OutputFormat format) override;
int32_t SetLocation(float latitude, float longitude) override;
int32_t SetRotation(int32_t rotation) override;
int32_t SetParameter(const Format &generalFormat) override;
int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) override;
int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override;
int32_t Start() override;
int32_t WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr<AVSharedMemory> &sampleBuffer, AVCodecBufferInfo info) override;
int32_t WriteSampleBuffer(std::shared_ptr<AVSharedMemory> sampleBuffer, const TrackSampleInfo &info) override;
int32_t Stop() override;
void Release() override;
void AVCodecServerDied();
private:
std::mutex mutex_;
sptr<IAVMuxerService> muxerProxy_ = nullptr;
sptr<IStandardMuxerService> muxerProxy_ = nullptr;
};
} // namespace Media
} // namespace OHOS

View File

@ -1,181 +0,0 @@
/*
* Copyright (C) 2022 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 "avmuxer_proxy.h"
#include "avcodec_log.h"
#include "avcodec_errors.h"
#include "avsharedmemory_ipc.h"
#include "avcodec_parcel.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMuxerProxy"};
}
namespace OHOS {
namespace Media {
AVMuxerProxy::AVMuxerProxy(const sptr<IRemoteObject> &impl)
: IRemoteProxy<IAVMuxerService>(impl)
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
}
AVMuxerProxy::~AVMuxerProxy()
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
}
int32_t AVMuxerProxy::DestroyStub()
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor");
int32_t ret = Remote()->SendRequest(DESTROY_STUB, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call DestroyStub");
return reply.ReadInt32();
}
int32_t AVMuxerProxy::Init()
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor");
int32_t ret = Remote()->SendRequest(INIT, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call Init");
return reply.ReadInt32();
}
int32_t AVMuxerProxy::SetLocation(float latitude, float longitude)
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor");
data.WriteFloat(latitude);
data.WriteFloat(longitude);
int32_t ret = Remote()->SendRequest(SET_LOCATION, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetLocation");
return reply.ReadInt32();
}
int32_t AVMuxerProxy::SetRotation(int32_t rotation)
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor");
data.WriteInt32(rotation);
int32_t ret = Remote()->SendRequest(SET_ROTATION, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetRotation");
return reply.ReadInt32();
}
int32_t AVMuxerProxy::SetParameter(const Format &generalFormat)
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor");
AVCodecParcel::Marshalling(data, generalFormat);
int32_t ret = Remote()->SendRequest(SET_PARAMETER, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, "SetParameter failed");
return reply.ReadInt32();
}
int32_t AVMuxerProxy::AddTrack(uint32_t &trackIndex, const Format &trackFormat)
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor");
data.WriteInt32(trackIndex);
AVCodecParcel::Marshalling(data, trackFormat);
int32_t ret = Remote()->SendRequest(ADD_TRACK, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call AddTrack");
return reply.ReadInt32();
}
int32_t AVMuxerProxy::Start()
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor");
int32_t ret = Remote()->SendRequest(START, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call Start");
return reply.ReadInt32();
}
int32_t AVMuxerProxy::WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr<AVSharedMemory> &sampleBuffer, AVCodecBufferInfo info)
{
CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, AVCS_ERR_INVALID_VAL, "sampleBuffer is nullptr");
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!");
data.WriteInt32(trackIndex);
WriteAVSharedMemoryToParcel(sampleBuffer, data);
data.WriteInt64(info.presentationTimeUs);
data.WriteInt32(info.size);
data.WriteInt32(info.offset);
// data.WriteInt32(info.flag);
int32_t ret = Remote()->SendRequest(WRITE_SAMPLE_BUFFER, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call WriteTrackSample");
return reply.ReadInt32();
}
int32_t AVMuxerProxy::Stop()
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!");
int ret = Remote()->SendRequest(STOP, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call Stop");
return reply.ReadInt32();
}
} // namespace Media
} // namespace OHOS

View File

@ -1,252 +0,0 @@
/*
* Copyright (C) 2022 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 "avmuxer_stub.h"
#include "unistd.h"
#include "avcodec_server_manager.h"
#include "avcodec_errors.h"
#include "avcodec_log.h"
#include "avsharedmemory_ipc.h"
#include "avcodec_parcel.h"
#include "avcodec_xcollie.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMuxerStub"};
}
namespace OHOS {
namespace Media {
sptr<AVMuxerStub> AVMuxerStub::Create()
{
sptr<AVMuxerStub> muxerStub = new(std::nothrow) AVMuxerStub();
CHECK_AND_RETURN_RET_LOG(muxerStub != nullptr, nullptr, "Failed to create muxer service stub");
int32_t ret = muxerStub->InitStub();
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Failed to init AVMuxerStub");
return muxerStub;
}
AVMuxerStub::AVMuxerStub()
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
}
AVMuxerStub::~AVMuxerStub()
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
}
int32_t AVMuxerStub::InitStub()
{
muxerServer_ = AVMuxerServer::Create();
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Failed to create muxer server");
muxerFuncs_[INIT] = &AVMuxerStub::Init;
muxerFuncs_[SET_LOCATION] = &AVMuxerStub::SetLocation;
muxerFuncs_[SET_ROTATION] = &AVMuxerStub::SetRotation;
muxerFuncs_[SET_PARAMETER] = &AVMuxerStub::SetParameter;
muxerFuncs_[ADD_TRACK] = &AVMuxerStub::AddTrack;
muxerFuncs_[START] = &AVMuxerStub::Start;
muxerFuncs_[WRITE_SAMPLE_BUFFER] = &AVMuxerStub::WriteSampleBuffer;
muxerFuncs_[STOP] = &AVMuxerStub::Stop;
muxerFuncs_[DESTROY_STUB] = &AVMuxerStub::DestroyStub;
return AVCS_ERR_OK;
}
int32_t AVMuxerStub::DestroyStub()
{
muxerServer_ = nullptr;
AVCodecServerManager::GetInstance().DestroyStubObject(AVCodecServerManager::MUXER, AsObject());
return AVCS_ERR_OK;
}
int AVMuxerStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
AVCODEC_LOGI("Stub: OnRemoteRequest of code: %{public}u is received", code);
auto remoteDescriptor = data.ReadInterfaceToken();
if (AVMuxerStub::GetDescriptor() != remoteDescriptor) {
AVCODEC_LOGE("Invalid descriptor");
return AVCS_ERR_INVALID_OPERATION;
}
auto itFunc = muxerFuncs_.find(code);
if (itFunc != muxerFuncs_.end()) {
auto memberFunc = itFunc->second;
if (memberFunc != nullptr) {
int32_t ret = -1;
COLLIE_LISTEN(ret = (this->*memberFunc)(data, reply),
"AVMuxerStub::OnRemoteRequest");
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call memberFunc");
return AVCS_ERR_OK;
}
}
AVCODEC_LOGW("Failed to find corresponding function");
return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
}
int32_t AVMuxerStub::Init()
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr");
return muxerServer_->Init();
}
int32_t AVMuxerStub::SetLocation(float latitude, float longitude)
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr");
return muxerServer_->SetLocation(latitude, longitude);
}
int32_t AVMuxerStub::SetRotation(int32_t rotation)
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr");
return muxerServer_->SetRotation(rotation);
}
int32_t AVMuxerStub::SetParameter(const Format &generalFormat)
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr");
return muxerServer_->SetParameter(generalFormat);
}
int32_t AVMuxerStub::AddTrack(uint32_t &trackIndex, const Format &trackFormat)
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr");
return muxerServer_->AddTrack(trackIndex, trackFormat);
}
int32_t AVMuxerStub::Start()
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr");
return muxerServer_->Start();
}
int32_t AVMuxerStub::WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr<AVSharedMemory> &sampleBuffer, AVCodecBufferInfo info)
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr");
return muxerServer_->WriteSampleBuffer(trackIndex, sampleBuffer, info);
}
int32_t AVMuxerStub::Stop()
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr");
return muxerServer_->Stop();
}
int32_t AVMuxerStub::DumpInfo(int32_t fd)
{
std::string dumpInfo;
dumpInfo += "# AVMuxerStub";
GetDumpInfo(dumpInfo);
CHECK_AND_RETURN_RET_LOG(fd != -1, AVCS_ERR_INVALID_VAL, "Attempt to write to a invalid fd: %{public}d", fd);
write(fd, dumpInfo.c_str(), dumpInfo.size());
return AVCS_ERR_OK;
}
int32_t AVMuxerStub::Init(MessageParcel &data, MessageParcel &reply)
{
// TODO: 补充LOG说明
(void)data;
(void)reply;
bool ret = reply.WriteInt32(Init());
CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed");
return AVCS_ERR_OK;
}
int32_t AVMuxerStub::DestroyStub(MessageParcel &data, MessageParcel &reply)
{
(void)data;
bool ret = reply.WriteInt32(DestroyStub());
CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed");
return AVCS_ERR_OK;
}
int32_t AVMuxerStub::SetLocation(MessageParcel &data, MessageParcel &reply)
{
float latitude = data.ReadFloat();
float longitude = data.ReadFloat();
bool ret = reply.WriteInt32(SetLocation(latitude, longitude));
CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed");
return AVCS_ERR_OK;
}
int32_t AVMuxerStub::SetRotation(MessageParcel &data, MessageParcel &reply)
{
int32_t rotation = data.ReadInt32();
bool ret = reply.WriteInt32(SetRotation(rotation));
CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed");
return AVCS_ERR_OK;
}
int32_t AVMuxerStub::SetParameter(MessageParcel &data, MessageParcel &reply)
{
Format format;
AVCodecParcel::Unmarshalling(data, format);
bool ret = reply.WriteInt32(SetParameter(format));
CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed");
return AVCS_ERR_OK;
}
int32_t AVMuxerStub::AddTrack(MessageParcel &data, MessageParcel &reply)
{
Format generalFormat;
uint32_t trackIndex = data.ReadInt32();
(void)AVCodecParcel::Unmarshalling(data, generalFormat);
bool ret = reply.WriteInt32(AddTrack(trackIndex, generalFormat));
CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed");
return AVCS_ERR_OK;
}
int32_t AVMuxerStub::Start(MessageParcel &data, MessageParcel &reply)
{
(void)data;
bool ret = reply.WriteInt32(Start());
CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed");
return AVCS_ERR_OK;
}
int32_t AVMuxerStub::WriteSampleBuffer(MessageParcel &data, MessageParcel &reply)
{
(void)data;
(void)reply;
uint32_t trackIndex = data.ReadInt32();
std::shared_ptr<AVSharedMemory> sampleBuffer = ReadAVSharedMemoryFromParcel(data);
AVCodecBufferInfo bufferInfo;
bufferInfo.presentationTimeUs = data.ReadInt64();
bufferInfo.size = data.ReadInt32();
bufferInfo.offset = data.ReadInt32();
bool ret = reply.WriteInt32(WriteSampleBuffer(trackIndex, sampleBuffer, bufferInfo));
CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed");
return AVCS_ERR_OK;
}
int32_t AVMuxerStub::Stop(MessageParcel &data, MessageParcel &reply)
{
(void)data;
bool ret = reply.WriteInt32(Stop());
CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed");
return AVCS_ERR_OK;
}
int32_t AVMuxerStub::GetDumpInfo(std::string& dumpInfo)
{
dumpInfo += "## pid: " + std::to_string(getpid());
dumpInfo += "## uid: " + std::to_string(getuid());
return AVCS_ERR_OK;
}
} // namespace Media
} // namespace OHOS

View File

@ -16,39 +16,37 @@
#ifndef I_STANDARD_MUXER_SERVICE_H
#define I_STANDARD_MUXER_SERVICE_H
#include "avcodec_info.h"
#include "avcodec_common.h"
#include "i_muxer_service.h"
#include "iremote_proxy.h"
namespace OHOS {
namespace Media {
class IAVMuxerService : public IRemoteBroker {
class IStandardMuxerService : public IRemoteBroker {
public:
virtual ~IAVMuxerService() = default;
virtual int32_t Init() = 0;
virtual ~IStandardMuxerService() = default;
virtual int32_t InitParameter(int32_t fd, OutputFormat format) = 0;
virtual int32_t SetLocation(float latitude, float longitude) = 0;
virtual int32_t SetRotation(int32_t rotation) = 0;
virtual int32_t SetParameter(const Format &generalFormat) = 0;
virtual int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) = 0;
virtual int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) = 0;
virtual int32_t Start() = 0;
virtual int32_t WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr<AVSharedMemory> &sampleBuffer, AVCodecBufferInfo info) = 0;
virtual int32_t WriteSampleBuffer(std::shared_ptr<AVSharedMemory> sampleBuffer, const TrackSampleInfo &info) = 0;
virtual int32_t Stop() = 0;
virtual void Release() = 0;
virtual int32_t DestroyStub() = 0;
virtual int32_t DestroyStub() = 0;
enum MuxerServiceMsg {
INIT,
INIT_PARAMETER = 0,
SET_LOCATION,
SET_ROTATION,
SET_PARAMETER,
ADD_TRACK,
START,
WRITE_SAMPLE_BUFFER,
STOP,
DESTROY_STUB,
RELEASE,
DESTROY,
};
DECLARE_INTERFACE_DESCRIPTOR(u"IAVMuxerService");
DECLARE_INTERFACE_DESCRIPTOR(u"IStandardMuxerServiceq1a");
};
} // namespace Media
} // namespace OHOS

View File

@ -0,0 +1,181 @@
/*
* Copyright (C) 2021 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 "muxer_service_proxy.h"
#include "avcodec_errors.h"
#include "avcodec_log.h"
#include "avsharedmemory_ipc.h"
#include "avcodec_parcel.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MuxerServiceProxy"};
}
namespace OHOS {
namespace Media {
MuxerServiceProxy::MuxerServiceProxy(const sptr<IRemoteObject> &impl)
: IRemoteProxy<IStandardMuxerService>(impl)
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
}
MuxerServiceProxy::~MuxerServiceProxy()
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
}
int32_t MuxerServiceProxy::InitParameter(int32_t fd, OutputFormat format)
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!");
CHECK_AND_RETURN_RET_LOG(data.WriteFileDescriptor(fd), AVCS_ERR_UNKNOWN, "WriteFileDescriptor failed!");
CHECK_AND_RETURN_RET_LOG(data.WriteInt32(format), AVCS_ERR_UNKNOWN, "WriteInt32 failed!");
int error = Remote()->SendRequest(INIT_PARAMETER, data, reply, option);
CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, "Call InitParameter failed, error: %{public}d", error);
return reply.ReadInt32();
}
int32_t MuxerServiceProxy::SetLocation(float latitude, float longitude)
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!");
CHECK_AND_RETURN_RET_LOG(data.WriteFloat(latitude), AVCS_ERR_UNKNOWN, "WriteFloat failed!");
CHECK_AND_RETURN_RET_LOG(data.WriteFloat(longitude), AVCS_ERR_UNKNOWN, "WriteFloat failed!");
int32_t ret = Remote()->SendRequest(SET_LOCATION, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "SetLocation failed, error: %{public}d", ret);
return reply.ReadInt32();
}
int32_t MuxerServiceProxy::SetRotation(int32_t rotation)
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!");
CHECK_AND_RETURN_RET_LOG(data.WriteInt32(rotation), AVCS_ERR_UNKNOWN, "WriteInt32 failed!");
int32_t ret = Remote()->SendRequest(SET_ROTATION, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "SetRotation failed, error: %{public}d", ret);
return reply.ReadInt32();
}
int32_t MuxerServiceProxy::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc)
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!");
AVCodecParcel::Marshalling(data, trackDesc);
int32_t ret = Remote()->SendRequest(ADD_TRACK, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "AddTrack failed, error: %{public}d", ret);
trackIndex = reply.ReadInt32();
return reply.ReadInt32();
}
int32_t MuxerServiceProxy::Start()
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!");
int32_t ret = Remote()->SendRequest(START, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Start failed, error: %{public}d", ret);
return reply.ReadInt32();
}
int32_t MuxerServiceProxy::WriteSampleBuffer(std::shared_ptr<AVSharedMemory> sampleBuffer, const TrackSampleInfo &info)
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!");
WriteAVSharedMemoryToParcel(sampleBuffer, data);
CHECK_AND_RETURN_RET_LOG(data.WriteUint32(info.trackIndex), AVCS_ERR_UNKNOWN, "Write track index failed!");
CHECK_AND_RETURN_RET_LOG(data.WriteInt64(info.timeUs), AVCS_ERR_UNKNOWN, "Write timeUs failed!");
CHECK_AND_RETURN_RET_LOG(data.WriteUint32(info.size), AVCS_ERR_UNKNOWN, "Write size failed!");
CHECK_AND_RETURN_RET_LOG(data.WriteUint32(info.flags), AVCS_ERR_UNKNOWN, "Write flags failed!");
int32_t ret = Remote()->SendRequest(WRITE_SAMPLE_BUFFER, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "WriteSampleBuffer failed, error: %{public}d", ret);
return reply.ReadInt32();
}
int32_t MuxerServiceProxy::Stop()
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!");
int32_t ret = Remote()->SendRequest(STOP, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Stop failed, error: %{public}d", ret);
return reply.ReadInt32();
}
int32_t MuxerServiceProxy::DestroyStub()
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor());
CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!");
int ret = Remote()->SendRequest(DESTROY, data, reply, option);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Call DestroyStub failed, error: %{public}d", ret);
return reply.ReadInt32();
}
void MuxerServiceProxy::Release()
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor());
CHECK_AND_RETURN_LOG(token, "Write descriptor failed!");
int ret = Remote()->SendRequest(RELEASE, data, reply, option);
CHECK_AND_RETURN_LOG(ret == AVCS_ERR_OK, " Call Release failed, error: %{public}d", ret);
}
} // namespace Media
} // namespace OHOS

View File

@ -16,27 +16,26 @@
#ifndef MUXER_SERVICE_PROXY_H
#define MUXER_SERVICE_PROXY_H
#include "i_avmuxer_service.h"
#include "i_standard_muxer_service.h"
namespace OHOS {
namespace Media {
class AVMuxerProxy : public IRemoteProxy<IAVMuxerService>, public NoCopyable {
class MuxerServiceProxy : public IRemoteProxy<IStandardMuxerService>, public NoCopyable {
public:
explicit AVMuxerProxy(const sptr<IRemoteObject> &impl);
virtual ~AVMuxerProxy();
explicit MuxerServiceProxy(const sptr<IRemoteObject> &impl);
virtual ~MuxerServiceProxy();
int32_t Init() override;
int32_t InitParameter(int32_t fd, OutputFormat format) override;
int32_t SetLocation(float latitude, float longitude) override;
int32_t SetRotation(int32_t rotation) override;
int32_t SetParameter(const Format &generalFormat) override;
int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) override;
int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override;
int32_t Start() override;
int32_t WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr<AVSharedMemory> &sampleBuffer, AVCodecBufferInfo info) override;
int32_t WriteSampleBuffer(std::shared_ptr<AVSharedMemory> sampleBuffer, const TrackSampleInfo &info) override;
int32_t Stop() override;
void Release() override;
int32_t DestroyStub() override;
private:
static inline BrokerDelegator<AVMuxerProxy> delegator_;
static inline BrokerDelegator<MuxerServiceProxy> delegator_;
};
} // namespace Media
} // namespace OHOS

View File

@ -0,0 +1,227 @@
/*
* Copyright (C) 2022 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 "muxer_service_stub.h"
#include "avcodec_server_manager.h"
#include "avcodec_errors.h"
#include "avcodec_log.h"
#include "avsharedmemory_ipc.h"
#include "avcodec_parcel.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MuxerServiceStub"};
}
namespace OHOS {
namespace Media {
sptr<MuxerServiceStub> MuxerServiceStub::Create()
{
sptr<MuxerServiceStub> muxerStub = new(std::nothrow) MuxerServiceStub();
CHECK_AND_RETURN_RET_LOG(muxerStub != nullptr, nullptr, "Create muxer service stub failed");
int32_t ret = muxerStub->Init();
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Init MuxerServiceStub failed to ");
return muxerStub;
}
MuxerServiceStub::MuxerServiceStub()
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
}
MuxerServiceStub::~MuxerServiceStub()
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
}
int32_t MuxerServiceStub::Init()
{
muxerServer_ = MuxerServer::Create();
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Create muxer server failed");
muxerFuncs_[INIT_PARAMETER] = &MuxerServiceStub::InitParameter;
muxerFuncs_[SET_LOCATION] = &MuxerServiceStub::SetLocation;
muxerFuncs_[SET_ROTATION] = &MuxerServiceStub::SetRotation;
muxerFuncs_[ADD_TRACK] = &MuxerServiceStub::AddTrack;
muxerFuncs_[START] = &MuxerServiceStub::Start;
muxerFuncs_[WRITE_SAMPLE_BUFFER] = &MuxerServiceStub::WriteSampleBuffer;
muxerFuncs_[STOP] = &MuxerServiceStub::Stop;
muxerFuncs_[RELEASE] = &MuxerServiceStub::Release;
muxerFuncs_[DESTROY] = &MuxerServiceStub::DestroyStub;
return AVCS_ERR_OK;
}
int MuxerServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
auto remoteDescriptor = data.ReadInterfaceToken();
if (MuxerServiceStub::GetDescriptor() != remoteDescriptor) {
AVCODEC_LOGE("Invalid descriptor");
return AVCS_ERR_INVALID_OPERATION;
}
auto itFunc = muxerFuncs_.find(code);
if (itFunc != muxerFuncs_.end()) {
auto memberFunc = itFunc->second;
if (memberFunc != nullptr) {
int32_t ret = (this->*memberFunc)(data, reply);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call memberFunc");
return AVCS_ERR_OK;
}
}
AVCODEC_LOGW("Failed to find corresponding function");
return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
}
int32_t MuxerServiceStub::InitParameter(int32_t fd, OutputFormat format)
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerServer_->InitParameter(fd, format);
}
int32_t MuxerServiceStub::SetLocation(float latitude, float longitude)
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerServer_->SetLocation(latitude, longitude);
}
int32_t MuxerServiceStub::SetRotation(int32_t rotation)
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerServer_->SetRotation(rotation);
}
int32_t MuxerServiceStub::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc)
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerServer_->AddTrack(trackIndex, trackDesc);
}
int32_t MuxerServiceStub::Start()
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerServer_->Start();
}
int32_t MuxerServiceStub::WriteSampleBuffer(std::shared_ptr<AVSharedMemory> sampleBuffer, const TrackSampleInfo &info)
{
CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, AVCS_ERR_INVALID_VAL, "sampleData is nullptr");
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerServer_->WriteSampleBuffer(sampleBuffer, info);
}
int32_t MuxerServiceStub::Stop()
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return muxerServer_->Stop();
}
void MuxerServiceStub::Release()
{
CHECK_AND_RETURN_LOG(muxerServer_ != nullptr, "Muxer Service does not exist");
muxerServer_->Release();
}
int32_t MuxerServiceStub::DestroyStub()
{
muxerServer_ = nullptr;
AVCodecServerManager::GetInstance().DestroyStubObject(AVCodecServerManager::MUXER, AsObject());
return AVCS_ERR_OK;
}
int32_t MuxerServiceStub::DumpInfo(int32_t fd)
{
CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist");
return std::static_pointer_cast<MuxerServer>(muxerServer_)->DumpInfo(fd);
}
int32_t MuxerServiceStub::InitParameter(MessageParcel &data, MessageParcel &reply)
{
int32_t fd = data.ReadFileDescriptor();
OutputFormat format = static_cast<OutputFormat>(data.ReadInt32());
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(InitParameter(fd, format)), AVCS_ERR_UNKNOWN, "Reply InitParameter failed!");
return AVCS_ERR_OK;
}
int32_t MuxerServiceStub::SetLocation(MessageParcel &data, MessageParcel &reply)
{
float latitude = data.ReadFloat();
float longitude = data.ReadFloat();
int32_t ret = SetLocation(latitude, longitude);
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(ret), AVCS_ERR_UNKNOWN, "Reply SetLocation failed!");
return AVCS_ERR_OK;
}
int32_t MuxerServiceStub::SetRotation(MessageParcel &data, MessageParcel &reply)
{
int32_t rotation = data.ReadInt32();
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(SetRotation(rotation)), AVCS_ERR_UNKNOWN, "WriteInt32 failed!");
return AVCS_ERR_OK;
}
int32_t MuxerServiceStub::AddTrack(MessageParcel &data, MessageParcel &reply)
{
MediaDescription trackDesc;
(void)AVCodecParcel::Unmarshalling(data, trackDesc);
int32_t trackIndex = -1;
int32_t ret = AddTrack(trackIndex, trackDesc);
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(trackIndex), AVCS_ERR_UNKNOWN, "Reply AddTrack failed!");
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(ret), AVCS_ERR_UNKNOWN, "Reply AddTrack failed!");
return AVCS_ERR_OK;
}
int32_t MuxerServiceStub::Start(MessageParcel &data, MessageParcel &reply)
{
(void)data;
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(Start()), AVCS_ERR_UNKNOWN, "Reply Start failed!");
return AVCS_ERR_OK;
}
int32_t MuxerServiceStub::WriteSampleBuffer(MessageParcel &data, MessageParcel &reply)
{
std::shared_ptr<AVSharedMemory> sampleBuffer = ReadAVSharedMemoryFromParcel(data);
CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, AVCS_ERR_UNKNOWN, "Read sampleBuffer from parcel failed!");
TrackSampleInfo info;
info.trackIndex = data.ReadUint32();
info.timeUs = data.ReadInt64();
info.size = data.ReadUint32();
info.flags = data.ReadUint32();
int32_t ret = WriteSampleBuffer(sampleBuffer, info);
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(ret), AVCS_ERR_UNKNOWN, "Reply WriteSampleBuffer failed!");
return AVCS_ERR_OK;
}
int32_t MuxerServiceStub::Stop(MessageParcel &data, MessageParcel &reply)
{
(void)data;
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(Stop()), AVCS_ERR_UNKNOWN, "Reply Stop failed!");
return AVCS_ERR_OK;
}
int32_t MuxerServiceStub::Release(MessageParcel &data, MessageParcel &reply)
{
(void)data;
(void)reply;
Release();
return AVCS_ERR_OK;
}
int32_t MuxerServiceStub::DestroyStub(MessageParcel &data, MessageParcel &reply)
{
(void)data;
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(DestroyStub()), AVCS_ERR_UNKNOWN, "Reply DestroyStub failed!");
return AVCS_ERR_OK;
}
} // namespace Media
} // namespace OHOS

View File

@ -16,50 +16,46 @@
#ifndef MUXER_SERVICE_STUB_H
#define MUXER_SERVICE_STUB_H
#include <string>
#include "i_avmuxer_service.h"
#include "avmuxer_server.h"
#include "i_standard_muxer_service.h"
#include "muxer_server.h"
#include "iremote_stub.h"
namespace OHOS {
namespace Media {
class AVMuxerStub : public IRemoteStub<IAVMuxerService>, public NoCopyable {
class MuxerServiceStub : public IRemoteStub<IStandardMuxerService>, public NoCopyable {
public:
static sptr<AVMuxerStub> Create();
virtual ~AVMuxerStub();
static sptr<MuxerServiceStub> Create();
virtual ~MuxerServiceStub();
int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override;
using MuxerStubFunc = int32_t(AVMuxerStub::*)(MessageParcel &data, MessageParcel &reply);
using MuxerStubFunc = int32_t(MuxerServiceStub::*)(MessageParcel &data, MessageParcel &reply);
int32_t Init() override;
int32_t InitParameter(int32_t fd, OutputFormat format) override;
int32_t SetLocation(float latitude, float longitude) override;
int32_t SetRotation(int32_t rotation) override;
int32_t SetParameter(const Format &generalFormat) override;
int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) override;
int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override;
int32_t Start() override;
int32_t WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr<AVSharedMemory> &sampleBuffer, AVCodecBufferInfo info) override;
int32_t WriteSampleBuffer(std::shared_ptr<AVSharedMemory> sampleBuffer, const TrackSampleInfo &info) override;
int32_t Stop() override;
int32_t DumpInfo(int32_t fd);
void Release() override;
int32_t DestroyStub() override;
int32_t DumpInfo(int32_t fd);
private:
AVMuxerStub();
int32_t InitStub();
int32_t Init(MessageParcel &data, MessageParcel &reply);
MuxerServiceStub();
int32_t Init();
int32_t InitParameter(MessageParcel &data, MessageParcel &reply);
int32_t SetLocation(MessageParcel &data, MessageParcel &reply);
int32_t SetRotation(MessageParcel &data, MessageParcel &reply);
int32_t SetParameter(MessageParcel &data, MessageParcel &reply);
int32_t AddTrack(MessageParcel &data, MessageParcel &reply);
int32_t Start(MessageParcel &data, MessageParcel &reply);
int32_t WriteSampleBuffer(MessageParcel &data, MessageParcel &reply);
int32_t Stop(MessageParcel &data, MessageParcel &reply);
int32_t GetDumpInfo(std::string& dumpInfo);
int32_t Release(MessageParcel &data, MessageParcel &reply);
int32_t DestroyStub(MessageParcel &data, MessageParcel &reply);
std::mutex mutex_;
std::shared_ptr<IAVMuxer> muxerServer_ = nullptr;
std::shared_ptr<IMuxerService> muxerServer_ {nullptr};
std::map<uint32_t, MuxerStubFunc> muxerFuncs_;
};
} // namespace Media
} // namespace OHOS
#endif
#endif // MUXER_SERVICE_STUB_H

View File

@ -1,122 +0,0 @@
/*
* Copyright (C) 2022 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 "avmuxer_server.h"
#include "avcodec_errors.h"
#include "avcodec_log.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMuxerServer"};
}
namespace OHOS {
namespace Media {
std::shared_ptr<IAVMuxer> AVMuxerServer::Create()
{
std::shared_ptr<AVMuxerServer> muxerServer = std::make_shared<AVMuxerServer>();
CHECK_AND_RETURN_RET_LOG(muxerServer != nullptr, nullptr, "Muxer Service does not exist");
int32_t ret = muxerServer->InitServer();
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Failed to init muxer server");
return muxerServer;
}
AVMuxerServer::AVMuxerServer()
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
}
AVMuxerServer::~AVMuxerServer()
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
}
int32_t AVMuxerServer::InitServer()
{
return AVCS_ERR_OK;
}
int32_t AVMuxerServer::Init()
{
std::lock_guard<std::mutex> lock(mutex_);
return AVCS_ERR_OK;
}
int32_t AVMuxerServer::SetLocation(float latitude, float longitude)
{
// TODO:achieve it
(void)latitude;
(void)longitude;
std::lock_guard<std::mutex> lock(mutex_);
return AVCS_ERR_OK;
}
int32_t AVMuxerServer::SetRotation(int32_t rotation)
{
// TODO:achieve it
(void)rotation;
std::lock_guard<std::mutex> lock(mutex_);
return AVCS_ERR_OK;
}
int32_t AVMuxerServer::SetParameter(const Format &generalFormat)
{
// TODO:achieve it
(void)generalFormat;
std::lock_guard<std::mutex> lock(mutex_);
return AVCS_ERR_OK;
}
int32_t AVMuxerServer::AddTrack(uint32_t &trackIndex, const Format &trackFormat)
{
// TODO:achieve it
(void)trackIndex;
(void)trackFormat;
std::lock_guard<std::mutex> lock(mutex_);
return AVCS_ERR_OK;
}
int32_t AVMuxerServer::Start()
{
std::lock_guard<std::mutex> lock(mutex_);
return AVCS_ERR_OK;
}
int32_t AVMuxerServer::WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr<AVSharedMemory> &sampleBuffer, AVCodecBufferInfo info)
{
// TODO:achieve it
(void)trackIndex;
(void)sampleBuffer;
(void)info;
std::lock_guard<std::mutex> lock(mutex_);
return AVCS_ERR_OK;
}
int32_t AVMuxerServer::Stop()
{
std::lock_guard<std::mutex> lock(mutex_);
return AVCS_ERR_OK;
}
} // namespace Media
} // namespace OHOS

View File

@ -0,0 +1,118 @@
/*
* Copyright (C) 2022 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 "muxer_server.h"
#include <unistd.h>
#include <fcntl.h>
#include "avcodec_errors.h"
#include "avcodec_log.h"
#include "ipc_skeleton.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MuxerServer"};
}
namespace OHOS {
namespace Media {
std::shared_ptr<IMuxerService> MuxerServer::Create()
{
std::shared_ptr<MuxerServer> muxerServer = std::make_shared<MuxerServer>();
CHECK_AND_RETURN_RET_LOG(muxerServer != nullptr, nullptr, "Muxer Service does not exist");
return muxerServer;
}
MuxerServer::MuxerServer()
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
appUid_ = IPCSkeleton::GetCallingUid();
appPid_ = IPCSkeleton::GetCallingPid();
}
MuxerServer::~MuxerServer()
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
muxerEngine_ = nullptr;
}
int32_t MuxerServer::InitParameter(int32_t fd, OutputFormat format)
{
muxerEngine_ = IMuxerEngineFactory::CreateMuxerEngine(appUid_, appPid_, fd, format);
CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Create muxer engine failed");
return AVCS_ERR_OK;
}
int32_t MuxerServer::SetLocation(float latitude, float longitude)
{
CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist");
int32_t ret = muxerEngine_->SetLocation(latitude, longitude);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetLocation");
return AVCS_ERR_OK;
}
int32_t MuxerServer::SetRotation(int32_t rotation)
{
CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist");
int32_t ret = muxerEngine_->SetRotation(rotation);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetRotation");
return AVCS_ERR_OK;
}
int32_t MuxerServer::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc)
{
CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist");
int32_t ret = muxerEngine_->AddTrack(trackIndex, trackDesc);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call AddTrack");
return AVCS_ERR_OK;
}
int32_t MuxerServer::Start()
{
CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist");
int32_t ret = muxerEngine_->Start();
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call Start");
return AVCS_ERR_OK;
}
int32_t MuxerServer::WriteSampleBuffer(std::shared_ptr<AVSharedMemory> sampleBuffer, const TrackSampleInfo &info)
{
CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, AVCS_ERR_INVALID_VAL, "sampleData is nullptr");
CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist");
int32_t ret = muxerEngine_->WriteSampleBuffer(sampleBuffer, info);
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call WriteSampleBuffer");
return AVCS_ERR_OK;
}
int32_t MuxerServer::Stop()
{
CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist");
int32_t ret = muxerEngine_->Stop();
CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call Stop");
return AVCS_ERR_OK;
}
void MuxerServer::Release()
{
CHECK_AND_RETURN_LOG(muxerEngine_ != nullptr, "muxer engine does not exist");
(void)muxerEngine_->Stop();
muxerEngine_ = nullptr;
}
int32_t MuxerServer::DumpInfo(int32_t fd)
{
CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist");
return muxerEngine_->DumpInfo(fd);
}
} // namespace Media
} // namespace OHOS

View File

@ -17,31 +17,32 @@
#define MUXER_SERVER_H
#include <mutex>
#include "i_avmuxer.h"
#include "i_muxer_service.h"
#include "i_muxer_engine.h"
#include "nocopyable.h"
namespace OHOS {
namespace Media {
class AVMuxerServer : public IAVMuxer, public NoCopyable {
namespace Media {
class MuxerServer : public IMuxerService, public NoCopyable {
public:
static std::shared_ptr<IAVMuxer> Create();
AVMuxerServer();
~AVMuxerServer();
static std::shared_ptr<IMuxerService> Create();
MuxerServer();
~MuxerServer();
int32_t Init() override;
int32_t InitParameter(int32_t fd, OutputFormat format) override;
int32_t SetLocation(float latitude, float longitude) override;
int32_t SetRotation(int32_t rotation) override;
int32_t SetParameter(const Format &generalFormat) override;
int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) override;
int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override;
int32_t Start() override;
int32_t WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr<AVSharedMemory> &sampleBuffer, AVCodecBufferInfo info) override;
int32_t WriteSampleBuffer(std::shared_ptr<AVSharedMemory> sampleBuffer, const TrackSampleInfo &info) override;
int32_t Stop() override;
void Release() override;
int32_t DumpInfo(int32_t fd);
private:
int32_t InitServer();
std::mutex mutex_;
// std::shared_ptr<IAVMuxerEngine> avmuxerEngine_ = nullptr;
// uint32_t trackNum_ = 0;
std::shared_ptr<IMuxerEngine> muxerEngine_ = nullptr;
int32_t appUid_ = 0;
int32_t appPid_ = 0;
};
} // namespace Media
} // namespace OHOS

View File

@ -21,9 +21,6 @@
#ifdef SUPPORT_DEMUXER
#include "i_avdemuxer_service.h"
#endif
#ifdef SUPPORT_MUXER
#include "i_avmuxer_service.h"
#endif
#ifdef SUPPORT_CODEC
#include "i_standard_codec_service.h"
#endif
@ -165,33 +162,33 @@ int32_t AVCodecClient::DestroyDemuxerService(std::shared_ptr<IAVDemuxer> demuxer
#endif
#ifdef SUPPORT_MUXER
std::shared_ptr<IAVMuxer> AVCodecClient::CreateMuxerService()
std::shared_ptr<IMuxerService> AVCodecClient::CreateMuxerService()
{
std::lock_guard<std::mutex> lock(mutex_);
if (!IsAlived()) {
AVCODEC_LOGE("av_codec service does not exist.");
AVCODEC_LOGE("avcodec service does not exist.");
return nullptr;
}
sptr<IRemoteObject> object = avCodecProxy_->GetSubSystemAbility(
IStandardAVCodecService::AVCodecSystemAbility::AVCODEC_MUXER, listenerStub_->AsObject());
CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "Muxer proxy object is nullptr.");
CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "muxer proxy object is nullptr.");
sptr<IAVMuxerService> muxerProxy = iface_cast<IAVMuxerService>(object);
CHECK_AND_RETURN_RET_LOG(muxerProxy != nullptr, nullptr, "Muxer proxy is nullptr.");
sptr<IStandardMuxerService> muxerProxy = iface_cast<IStandardMuxerService>(object);
CHECK_AND_RETURN_RET_LOG(muxerProxy != nullptr, nullptr, "muxer proxy is nullptr.");
std::shared_ptr<AVMuxerClient> muxerClient = AVMuxerClient::Create(muxerProxy);
CHECK_AND_RETURN_RET_LOG(muxerClient != nullptr, nullptr, "Failed to create muxer client.");
std::shared_ptr<MuxerClient> muxer = MuxerClient::Create(muxerProxy);
CHECK_AND_RETURN_RET_LOG(muxer != nullptr, nullptr, "failed to create muxer client.");
muxerClientList_.push_back(muxerClient);
return muxerClient;
muxerClientList_.push_back(muxer);
return muxer;
}
int32_t AVCodecClient::DestroyMuxerService(std::shared_ptr<IAVMuxer> muxerClient)
int32_t AVCodecClient::DestroyMuxerService(std::shared_ptr<IMuxerService> muxer)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(muxerClient != nullptr, AVCS_ERR_NO_MEMORY, "muxer client is nullptr.");
muxerClientList_.remove(muxerClient);
CHECK_AND_RETURN_RET_LOG(muxer != nullptr, AVCS_ERR_NO_MEMORY, "input muxer is nullptr.");
muxerClientList_.remove(muxer);
return AVCS_ERR_OK;
}
#endif
@ -237,7 +234,7 @@ sptr<IStandardAVCodecService> AVCodecClient::GetAVCodecProxy()
CHECK_AND_RETURN_RET_LOG(samgr != nullptr, nullptr, "system ability manager is nullptr.");
sptr<IRemoteObject> object = nullptr;
COLLIE_LISTEN(object = samgr->GetSystemAbility(OHOS::AVCODEC_SERVICE_ID),
COLLIE_LISTEN(object = samgr->GetSystemAbility(OHOS::AV_CODEC_SERVICE_ID),
"AVCodecClient::GetAVCodecProxy");
CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "avcodec object is nullptr.");
@ -295,9 +292,9 @@ void AVCodecClient::DoAVCodecServerDied()
#endif
#ifdef SUPPORT_MUXER
for (auto &it : muxerClientList_) {
auto muxerClient = std::static_pointer_cast<AVMuxerClient>(it);
if (muxerClient != nullptr) {
muxerClient->AVCodecServerDied();
auto muxer = std::static_pointer_cast<MuxerClient>(it);
if (muxer != nullptr) {
muxer->AVCodecServerDied();
}
}
#endif

View File

@ -25,7 +25,7 @@
#endif
#ifdef SUPPORT_MUXER
#include "avmuxer_client.h"
#include "muxer_client.h"
#endif
#ifdef SUPPORT_CODEC
@ -51,8 +51,8 @@ public:
#endif
#ifdef SUPPORT_MUXER
std::shared_ptr<IAVMuxer> CreateMuxerService() override;
int32_t DestroyMuxerService(std::shared_ptr<IAVMuxer> muxerClient) override;
std::shared_ptr<IMuxerService> CreateMuxerService() override;
int32_t DestroyMuxerService(std::shared_ptr<IMuxerService> muxer) override;
#endif
#ifdef SUPPORT_CODEC
@ -80,7 +80,7 @@ private:
std::list<std::shared_ptr<IAVDemuxer>> demuxerClientList_;
#endif
#ifdef SUPPORT_MUXER
std::list<std::shared_ptr<IAVMuxer>> muxerClientList_;
std::list<std::shared_ptr<IMuxerService>> muxerClientList_;
#endif
#ifdef SUPPORT_CODEC
std::list<std::shared_ptr<ICodecService>> codecClientList_;

View File

@ -47,7 +47,7 @@ bool AVCodecParcel::Marshalling(MessageParcel &parcel, const Format &format)
break;
case FORMAT_TYPE_ADDR:
(void)parcel.WriteInt32(static_cast<int32_t>(it->second.size));
(void)parcel.WriteBuffer(reinterpret_cast<const void *>(it->second.addr), it->second.size);
(void)parcel.WriteUnpadBuffer(reinterpret_cast<const void *>(it->second.addr), it->second.size);
break;
default:
AVCODEC_LOGE("fail to Marshalling Key: %{public}s", it->first.c_str());
@ -55,6 +55,7 @@ bool AVCodecParcel::Marshalling(MessageParcel &parcel, const Format &format)
}
AVCODEC_LOGD("success to Marshalling Key: %{public}s", it->first.c_str());
}
return true;
}
@ -82,7 +83,7 @@ bool AVCodecParcel::Unmarshalling(MessageParcel &parcel, Format &format)
break;
case FORMAT_TYPE_ADDR: {
auto addrSize = parcel.ReadInt32();
auto addr = parcel.ReadBuffer(static_cast<size_t>(addrSize));
auto addr = parcel.ReadUnpadBuffer(static_cast<size_t>(addrSize));
if (addr == nullptr) {
AVCODEC_LOGE("fail to ReadBuffer Key: %{public}s", key.c_str());
return false;

View File

@ -1,3 +1,18 @@
/*
* 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.
*/
#ifndef I_STANDARD_AVCODEC_LISTENER_H
#define I_STANDARD_AVCODEC_LISTENER_H

View File

@ -26,7 +26,7 @@ constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecSer
namespace OHOS {
namespace Media {
REGISTER_SYSTEM_ABILITY_BY_ID(AVCodecServer, AVCODEC_SERVICE_ID, true)
REGISTER_SYSTEM_ABILITY_BY_ID(AVCodecServer, AV_CODEC_SERVICE_ID, true)
AVCodecServer::AVCodecServer(int32_t systemAbilityId, bool runOnCreate) : SystemAbility(systemAbilityId, runOnCreate)
{
AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));

View File

@ -33,7 +33,7 @@
#include "avdemuxer_stub.h"
#endif
#ifdef SUPPORT_MUXER
#include "avmuxer_stub.h"
#include "muxer_service_stub.h"
#endif
#ifdef SUPPORT_SOURCE
#include "source_service_stub.h"
@ -100,10 +100,10 @@ int32_t AVCodecServerManager::Dump(int32_t fd, const std::vector<std::u16string>
#endif
#ifdef SUPPORT_MUXER
dumpString += "------------------AVMuxerServer------------------\n";
dumpString += "------------------MuxerServer------------------\n";
if (WriteInfo(fd, dumpString, dumperTbl_[StubType::MUXER],
argSets.find(u"muxer") != argSets.end()) != OHOS::NO_ERROR) {
AVCODEC_LOGW("Failed to write AVMuxerServer information");
AVCODEC_LOGW("Failed to write MuxerServer information");
return OHOS::INVALID_OPERATION;
}
#endif
@ -285,19 +285,19 @@ sptr<IRemoteObject> AVCodecServerManager::CreateMuxerStubObject()
"Please release the applied resources.", muxerStubMap_.size());
return nullptr;
}
sptr<AVMuxerStub> stub = AVMuxerStub::Create();
if (stub == nullptr) {
AVCODEC_LOGE("Failed to create AVMuxerStub");
sptr<MuxerServiceStub> muxerStub = MuxerServiceStub::Create();
if (muxerStub == nullptr) {
AVCODEC_LOGE("Create MuxerServiceStub failed");
return nullptr;
}
sptr<IRemoteObject> object = stub->AsObject();
sptr<IRemoteObject> object = muxerStub->AsObject();
if (object != nullptr) {
pid_t pid = IPCSkeleton::GetCallingPid();
muxerStubMap_[object] = pid;
Dumper dumper;
dumper.entry_ = [stub](int32_t fd) -> int32_t {
return stub->DumpInfo(fd);
dumper.entry_ = [muxer = muxerStub](int32_t fd) -> int32_t {
return muxer->DumpInfo(fd);
};
dumper.pid_ = pid;
dumper.uid_ = IPCSkeleton::GetCallingUid();
@ -379,7 +379,8 @@ void AVCodecServerManager::DestroyStubObject(StubType type, sptr<IRemoteObject>
case MUXER: {
auto it = find_if(muxerStubMap_.begin(), muxerStubMap_.end(), compare_func);
if (it != muxerStubMap_.end()) {
AVCODEC_LOGD("destroy muxer stub services(%{public}zu) pid(%{public}d).", muxerStubMap_.size(), pid);
AVCODEC_LOGD("destroy muxer stub services(%{public}zu) pid(%{public}d).",
muxerStubMap_.size(), pid);
(void)muxerStubMap_.erase(it);
return;
}

View File

@ -146,19 +146,19 @@ int32_t SourceServiceStub::DumpInfo(int32_t fd)
int32_t SourceServiceStub::Init(MessageParcel &data, MessageParcel &reply)
{
std::string uri = data.ReadString();
CHECK_AND_RETURN_RET(reply.WriteInt32(Init(uri)), AVCS_ERR_UNKNOWN);
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(Init(uri)), AVCS_ERR_UNKNOWN, "WriteInt32 failed!");
return AVCS_ERR_OK;
}
int32_t SourceServiceStub::GetTrackCount(MessageParcel &data, MessageParcel &reply)
{
CHECK_AND_RETURN_RET(reply.WriteInt32(GetTrackCount()), AVCS_ERR_UNKNOWN);
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(GetTrackCount()), AVCS_ERR_UNKNOWN, "WriteInt32 failed!");
return AVCS_ERR_OK;
}
int32_t SourceServiceStub::Destroy(MessageParcel &data, MessageParcel &reply)
{
CHECK_AND_RETURN_RET(reply.WriteInt32(Destroy()), AVCS_ERR_UNKNOWN);
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(Destroy()), AVCS_ERR_UNKNOWN, "WriteInt32 failed!");
return AVCS_ERR_OK;
}
@ -167,7 +167,7 @@ int32_t SourceServiceStub::SetParameter(MessageParcel &data, MessageParcel &repl
Format param;
(void)AVCodecParcel::Unmarshalling(data, param);
uint32_t trackId = data.ReadUint32();
CHECK_AND_RETURN_RET(reply.WriteInt32(SetParameter(param, trackId)), AVCS_ERR_UNKNOWN);
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(SetParameter(param, trackId)), AVCS_ERR_UNKNOWN, "WriteInt32 failed!");
return AVCS_ERR_OK;
}
@ -175,20 +175,20 @@ int32_t SourceServiceStub::GetTrackFormat(MessageParcel &data, MessageParcel &re
{
uint32_t trackId = data.ReadUint32();
Format format;
CHECK_AND_RETURN_RET(reply.WriteInt32(GetTrackFormat(format, trackId)), AVCS_ERR_UNKNOWN);
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(GetTrackFormat(format, trackId)), AVCS_ERR_UNKNOWN, "WriteInt32 failed!");
AVCodecParcel::Marshalling(reply, format);
return AVCS_ERR_OK;
}
int32_t SourceServiceStub::GetSourceAttr(MessageParcel &data, MessageParcel &reply)
{
CHECK_AND_RETURN_RET(reply.WriteUint64(GetSourceAttr()), AVCS_ERR_UNKNOWN);
CHECK_AND_RETURN_RET_LOG(reply.WriteUint64(GetSourceAttr()), AVCS_ERR_UNKNOWN, "WriteUint64 failed!");
return AVCS_ERR_OK;
}
int32_t SourceServiceStub::DestroyStub(MessageParcel &data, MessageParcel &reply)
{
CHECK_AND_RETURN_RET(reply.WriteInt32(DestroyStub()), AVCS_ERR_UNKNOWN);
CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(DestroyStub()), AVCS_ERR_UNKNOWN, "WriteInt32 failed!");
return AVCS_ERR_OK;
}

View File

@ -0,0 +1,146 @@
/*
* 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.
*/
#ifndef UTILS_BLOCK_QUEUE_H
#define UTILS_BLOCK_QUEUE_H
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <queue>
#include "avcodec_log.h"
namespace OHOS {
namespace Media {
namespace {
constexpr size_t DEFAULT_QUEUE_SIZE = 10;
}
template <typename T>
class BlockQueue {
public:
explicit BlockQueue(std::string name, size_t capacity = DEFAULT_QUEUE_SIZE)
: name_(std::move(name)), capacity_(capacity), isActive_(true)
{
}
~BlockQueue() = default;
size_t Size()
{
std::unique_lock<std::mutex> lock(mutex_);
return que_.size();
}
size_t Capacity()
{
return capacity_;
}
size_t Empty()
{
std::unique_lock<std::mutex> lock(mutex_);
return que_.empty();
}
bool Push(const T& block)
{
AVCODEC_LOGD("block queue %{public}s Push enter.", name_.c_str());
std::unique_lock<std::mutex> lock(mutex_);
if (!isActive_) {
AVCODEC_LOGD("block queue %{public}s is inactive for Push.", name_.c_str());
return false;
}
if (que_.size() >= capacity_) {
AVCODEC_LOGD("block queue %{public}s is full, please waiting for Pop.", name_.c_str());
condFull_.wait(lock, [this] { return !isActive_ || que_.size() < capacity_; });
}
if (!isActive_) {
AVCODEC_LOGD("block queue %{public}s: inactive: %{public}d, isFull: %{public}d.",
name_.c_str(), isActive_.load(), que_.size() < capacity_);
return false;
}
que_.push(block);
condEmpty_.notify_one();
AVCODEC_LOGD("block queue %{public}s Push ok.", name_.c_str());
return true;
}
T Pop()
{
AVCODEC_LOGD("block queue %{public}s Pop enter.", name_.c_str());
std::unique_lock<std::mutex> lock(mutex_);
if (que_.empty() && !isActive_) {
AVCODEC_LOGD("block queue %{public}s is inactive for Pop.", name_.c_str());
return {};
} else if (que_.empty() && isActive_) {
AVCODEC_LOGD("block queue %{public}s is empty, please waiting for Push.", name_.c_str());
condEmpty_.wait(lock, [this] { return !isActive_ || !que_.empty(); });
}
if (que_.empty()) {
AVCODEC_LOGD("block queue %{public}s: inactive: %{public}d, size: %{public}d.",
name_.c_str(), isActive_.load(), que_.size());
return {};
}
T element = que_.front();
que_.pop();
condFull_.notify_one();
AVCODEC_LOGD("block queue %{public}s Pop ok.", name_.c_str());
return element;
}
void Clear()
{
std::unique_lock<std::mutex> lock(mutex_);
ClearUnprotected();
}
void SetActive(bool active, bool cleanData = true)
{
std::unique_lock<std::mutex> lock(mutex_);
AVCODEC_LOGD("SetActive %{public}s: %{public}d.", name_.c_str(), isActive_.load());
isActive_ = active;
if (!active) {
if (cleanData) {
ClearUnprotected();
}
condEmpty_.notify_one();
}
}
private:
void ClearUnprotected()
{
if (que_.empty()) {
return;
}
bool needNotify = que_.size() == capacity_;
std::queue<T>().swap(que_);
if (needNotify) {
condFull_.notify_one();
}
}
std::mutex mutex_;
std::condition_variable condFull_;
std::condition_variable condEmpty_;
std::queue<T> que_;
std::string name_;
const size_t capacity_;
std::atomic<bool> isActive_;
const OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "BlockQueue"};
};
} // namespace Media
} // namespace OHOS
#endif // !UTILS_BLOCK_QUEUE_H

View File

@ -14,17 +14,21 @@
import("//build/ohos.gni")
import("//foundation/multimedia/av_codec/config.gni")
group("av_codec_demo_test") {
testonly = true
deps = []
if (multimedia_av_codec_support_test) {
deps += [ "nativedemo:av_codec_demo" ]
}
}
group("av_codec_unit_test") {
testonly = true
deps = []
}
group("av_codec_fuzz_test") {
testonly = true
deps = []
}
group("av_codec_demo_test") {
testonly = true
deps = [ "//foundation/multimedia/av_codec/test/nativedemo:av_codec_demo" ]
if (multimedia_av_codec_support_test) {
deps += [
"unittest:av_muxer_unit_test",
"unittest:format_unit_test",
]
}
}

View File

@ -16,18 +16,21 @@ import("//foundation/multimedia/av_codec/config.gni")
ohos_executable("av_codec_demo") {
include_dirs = [
"//foundation/multimedia/av_codec/test/nativedemo/avmuxer",
"//foundation/multimedia/av_codec/interfaces/kits/c",
"//foundation/multimedia/av_codec/interfaces/inner_api/native",
"//foundation/multimedia/av_codec/services/services/factory",
"//foundation/multimedia/av_codec/services/engine/plugin/core",
"//foundation/multimedia/av_codec/services/engine/plugin/interface",
"//foundation/multimedia/av_codec/services/dfx/include",
"//foundation/multimedia/av_codec/services/utils/include",
"./av_codec_audio",
"./audio_demo",
"./include",
"//foundation/multimedia/av_codec/interfaces/inner_api/native",
"//foundation/multimedia/av_codec/interfaces/kits/c",
"//foundation/multimedia/av_codec/services/utils/include",
"//foundation/multimedia/av_codec/services/dfx/include",
]
cflags = [
"-Wall",
"-std=c++17",
"-fno-rtti",
"-fno-exceptions",
"-fno-common",
@ -48,15 +51,27 @@ ohos_executable("av_codec_demo") {
"-Wno-deprecated-declarations",
]
cflags_cc = cflags
cflags_cc += ["-std=c++17"]
sources = [
"./av_codec_demo.cpp",
"//foundation/multimedia/av_codec/test/nativedemo/av_codec_demo.cpp",
"//foundation/multimedia/av_codec/test/nativedemo/avmuxer/avmuxer_demo_base.cpp",
"//foundation/multimedia/av_codec/test/nativedemo/avmuxer/avmuxer_demo.cpp",
"//foundation/multimedia/av_codec/test/nativedemo/avmuxer/avmuxer_engine_demo.cpp",
"//foundation/multimedia/av_codec/test/nativedemo/avmuxer/avmuxer_ffmpeg_demo.cpp",
"//foundation/multimedia/av_codec/test/nativedemo/avmuxer/avmuxer_demo_common.c",
"//foundation/multimedia/av_codec/test/nativedemo/avmuxer/native_avmuxer_demo.c",
"./audio_demo/avcodec_audio_encoder_inner_demo.cpp",
"./audio_demo/avcodec_audio_decoder_demo.cpp",
"./audio_demo/avcodec_audio_encoder_demo.cpp"
]
deps = [
"//foundation/multimedia/av_codec/interfaces/kits/c:native_av_codec_avmuxer",
"//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client",
"//foundation/multimedia/av_codec/services/services:av_codec_service",
"//foundation/multimedia/av_codec/services/utils:av_codec_format",
"//foundation/multimedia/av_codec/interfaces/kits/c:capi_packages"
]

View File

@ -0,0 +1,125 @@
/*
* 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 "avmuxer_demo.h"
#include <iostream>
#include <fstream>
#include <cstdio>
#include <unistd.h>
#include <fcntl.h>
#include <thread>
#include <vector>
#include "avcodec_errors.h"
namespace {
extern "C" {
extern char *RUN_NORMAL;
extern char *RUN_MUL_THREAD;
}
}
namespace OHOS {
namespace Media {
int AVMuxerDemo::DoWriteSampleBuffer(uint8_t *sampleBuffer, TrackSampleInfo &info)
{
if (avmuxer_ != nullptr &&
avmuxer_->WriteSampleBuffer(sampleBuffer, info) == AVCS_ERR_OK) {
return 0;
}
return -1;
}
int AVMuxerDemo::DoAddTrack(int32_t &trackIndex, MediaDescription &trackDesc)
{
int ret;
if ((ret = avmuxer_->AddTrack(trackIndex, trackDesc)) != AVCS_ERR_OK) {
std::cout<<"AVMuxerDemo::DoAddTrack failed! ret:"<<ret<<std::endl;
return -1;
}
return 0;
}
void AVMuxerDemo::DoRunMuxer(const std::string &runMode)
{
std::string outFileName = "mux_" + runMode + "_" + audioType_ + "_" + videoType_ + "_" + coverType_ + "." + format_;
outFd_ = open(outFileName.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
if (outFd_ < 0) {
std::cout << "Open file failed! filePath is: " << outFileName << std::endl;
return;
}
std::cout<<"==== open success! =====\noutputFileName: "<<outFileName<<"\n============"<<std::endl;
avmuxer_ = AVMuxerFactory::CreateAVMuxer(outFd_, outputFormat_);
if (avmuxer_ == nullptr) {
std::cout << "avmuxer_ is null" << std::endl;
return;
}
std::cout << "create muxer success " << avmuxer_ << std::endl;
if (avmuxer_->SetLocation(10, 10) != AVCS_ERR_OK
|| avmuxer_->SetRotation(0) != AVCS_ERR_OK) {
std::cout<<"set failed!"<<std::endl;
return;
}
AddAudioTrack(audioParams_);
AddVideoTrack(videoParams_);
AddCoverTrack(coverParams_);
std::cout << "add track success" << std::endl;
if (avmuxer_->Start() != AVCS_ERR_OK) {
return;
}
std::cout << "start muxer success" << std::endl;
if (coverParams_ != nullptr) {
WriteCoverSample();
}
std::cout<<"AVMuxerDemo::DoRunMuxer runMode is : "<<runMode<<std::endl;
if (runMode.compare(RUN_NORMAL) == 0) {
WriteTrackSample();
} else if (runMode.compare(RUN_MUL_THREAD) == 0) {
std::vector<std::thread> vecThread;
vecThread.emplace_back(MulThdWriteTrackSample, this, audioTrackId_, audioFile_);
vecThread.emplace_back(MulThdWriteTrackSample, this, videoTrackId_, videoFile_);
for (uint32_t i = 0; i < vecThread.size(); ++i) {
vecThread[i].join();
}
}
std::cout << "write muxer success" << std::endl;
if (avmuxer_->Stop() != AVCS_ERR_OK) {
return;
}
std::cout << "stop muxer success" << std::endl;
}
void AVMuxerDemo::DoRunMuxer()
{
DoRunMuxer(std::string(RUN_NORMAL));
}
void AVMuxerDemo::DoRunMultiThreadCase()
{
DoRunMuxer(std::string(RUN_MUL_THREAD));
}
} // namespace Media
} // namespace OHOS

View File

@ -0,0 +1,38 @@
/*
* 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.
*/
#ifndef AVMUXER_DEMO_H
#define AVMUXER_DEMO_H
#include "avmuxer.h"
#include "avmuxer_demo_base.h"
namespace OHOS {
namespace Media {
class AVMuxerDemo /*: public NoCopyable*/ : public AVMuxerDemoBase {
public:
AVMuxerDemo() = default;
~AVMuxerDemo() = default;
private:
void DoRunMuxer() override;
int DoWriteSampleBuffer(uint8_t *sampleBuffer, TrackSampleInfo &info) override;
int DoAddTrack(int32_t &trackIndex, MediaDescription &trackDesc) override;
void DoRunMultiThreadCase() override;
void DoRunMuxer(const std::string &runMode);
std::shared_ptr<AVMuxer> avmuxer_;
};
} // namespace Media
} // namespace OHOS
#endif // AVMUXER_DEMO_H

View File

@ -0,0 +1,501 @@
/*
* 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 "avmuxer_demo_base.h"
#include <unistd.h>
#include <iostream>
#include <fstream>
#include "avcodec_errors.h"
#include "avcodec_common.h"
namespace {
// constexpr uint32_t DATA_AUDIO_ID = 0;
// constexpr uint32_t DATA_VIDEO_ID = 1;
extern "C" {
extern AudioTrackParam g_audioMpegPar;
extern AudioTrackParam g_audioAacPar;
extern VideoTrackParam g_videoH264Par;
extern VideoTrackParam g_videoMpeg4Par;
extern VideoTrackParam g_jpegCoverPar;
extern VideoTrackParam g_pngCoverPar;
extern VideoTrackParam g_bmpCoverPar;
}
}
namespace OHOS {
namespace Media {
AVMuxerDemoBase::AVMuxerDemoBase()
{
}
std::shared_ptr<std::ifstream> OpenFile(const std::string &filePath)
{
auto file = std::make_shared<std::ifstream>();
file->open(filePath, std::ios::in | std::ios::binary);
if (file->is_open()) {
return file;
}
return nullptr;
}
int AVMuxerDemoBase::SelectMode()
{
// TODO:add muxer mode select
int num;
std::cout<<"\nplease select muxer type: 0.mp4 1.m4a"<<std::endl;
std::cin>>num;
switch (num)
{
case 0:
format_ = "mp4";
outputFormat_ = OUTPUT_FORMAT_MPEG_4;
break;
case 1:
format_ = "m4a";
outputFormat_ = OUTPUT_FORMAT_M4A;
break;
default:
format_ = "mp4";
outputFormat_ = OUTPUT_FORMAT_MPEG_4;
break;
}
std::cout<<"\nplease select audio file: 0.noAudio 1.aac 2.mpeg"<<std::endl;
std::cin>>num;
switch (num)
{
case 0:
audioType_ = "noAudio";
audioParams_ = nullptr;
break;
case 1:
audioType_ = "aac";
audioParams_ = &g_audioAacPar;
break;
case 2:
audioType_ = "mpeg";
audioParams_ = &g_audioMpegPar;
break;
default:
videoType_ = "noAudio";
audioParams_ = nullptr;
std::cout<<"do not support audio type index: "<<num<<", set to noAudio"<<std::endl;
break;
}
std::cout<<"please select video file:0.noVideo 1.h264 2.mpeg4"<<std::endl;
std::cin>>num;
switch (num)
{
case 0:
videoType_ = "noVideo";
videoParams_ = nullptr;
break;
case 1:
videoType_ = "h264";
videoParams_ = &g_videoH264Par;
break;
case 2:
videoType_ = "mpeg4";
videoParams_ = &g_videoMpeg4Par;
break;
default:
videoType_ = "noVideo";
videoParams_ = nullptr;
std::cout<<"do not support video type index: "<<", set to noVideo"<<num<<std::endl;
break;
}
std::cout<<"please select cover file:0.NoCover 1.jpg 2.png 3.bmp"<<std::endl;
std::cin>>num;
switch (num)
{
case 0:
coverType_ = "noCover";
coverParams_ = nullptr;
break;
case 1:
coverType_ = "jpg";
coverParams_ = &g_jpegCoverPar;
break;
case 2:
coverType_ = "png";
coverParams_ = &g_pngCoverPar;
break;
case 3:
coverType_ = "bmp";
coverParams_ = &g_bmpCoverPar;
break;
default:
coverType_ = "noCover";
coverParams_ = nullptr;
std::cout<<"do not support cover type index: "<<", set to noCover"<<num<<std::endl;
break;
}
return 0;
}
int AVMuxerDemoBase::SelectModeAndOpenFile()
{
if (SelectMode() != 0) {
return -1;
}
if (audioParams_ != nullptr) {
audioFile_ = OpenFile(audioParams_->fileName);
if (audioFile_ == nullptr) {
std::cout<<"open audio file failed! file name:"<<audioParams_->fileName<<std::endl;
return -1;
}
std::cout<<"open audio file success! file name:"<<audioParams_->fileName<<std::endl;
}
if (videoParams_ != nullptr) {
videoFile_ = OpenFile(videoParams_->fileName);
if (videoFile_ == nullptr) {
std::cout<<"open video file failed! file name:"<<videoParams_->fileName<<std::endl;
Reset();
return -1;
}
std::cout<<"video file success! file name:"<<videoParams_->fileName<<std::endl;
}
if (coverParams_ != nullptr) {
coverFile_ = OpenFile(coverParams_->fileName);
if (coverFile_ == nullptr) {
std::cout<<"open cover file failed! file name:"<<coverParams_->fileName<<std::endl;
Reset();
return -1;
}
std::cout<<"cover file success! file name:"<<coverParams_->fileName<<std::endl;
}
return 0;
}
void AVMuxerDemoBase::Reset()
{
if (outFd_ > 0) {
close(outFd_);
outFd_ = -1;
}
if (audioFile_ != nullptr) {
audioFile_->close();
audioFile_ = nullptr;
}
if (videoFile_ != nullptr) {
videoFile_->close();
videoFile_ = nullptr;
}
if (coverFile_ != nullptr) {
coverFile_->close();
coverFile_ = nullptr;
}
}
void AVMuxerDemoBase::RunCase()
{
if (SelectModeAndOpenFile() != 0) {
return;
}
DoRunMuxer();
Reset();
}
void AVMuxerDemoBase::RunMultiThreadCase()
{
std::cout<<"==== start AVMuxerDemoBase::RunMultiThreadCase ==="<<std::endl;
if (SelectModeAndOpenFile() != 0) {
return;
}
DoRunMultiThreadCase();
Reset();
}
void AVMuxerDemoBase::WriteSingleTrackSample(uint32_t trackId, std::shared_ptr<std::ifstream> file)
{
if (file == nullptr) {
std::cout<<"AVMuxerDemoBase::WriteTrackSample file si nullptr"<<std::endl;
return;
}
uint32_t flags = 0;
uint32_t dataSize = 0;
unsigned char *avMuxerDemoBuffer = nullptr;
uint32_t avMuxerDemoBufferSize = 0;
TrackSampleInfo info {trackId, 0, 0 ,0};
while(1) {
file->read((char *)&info.timeUs, sizeof(info.timeUs));
if (file->eof()) {
break;
}
file->read((char *)&flags, sizeof(flags));
if (file->eof()) {
break;
}
file->read((char *)&dataSize, sizeof(dataSize));
if (file->eof()) {
break;
}
if (avMuxerDemoBuffer != nullptr && dataSize > avMuxerDemoBufferSize) {
delete [] avMuxerDemoBuffer;
avMuxerDemoBuffer = nullptr;
avMuxerDemoBufferSize = 0;
}
if (avMuxerDemoBuffer == nullptr) {
avMuxerDemoBuffer = new unsigned char[dataSize];
avMuxerDemoBufferSize = dataSize;
}
file->read((char *)avMuxerDemoBuffer, dataSize);
if(file->eof()) {
break;
}
info.size = dataSize;
info.flags = 0;
if (flags != 0) {
info.flags |= AVCODEC_BUFFER_FLAG_SYNC_FRAME;
}
// std::cout<<"tracker id:"<<trackId<<" pts:"<<info.pts<<std::endl;
if (DoWriteSampleBuffer((uint8_t*)avMuxerDemoBuffer, info) != 0) {
std::cout<<"DoWriteSampleBuffer failed!"<<std::endl;
}
}
if (avMuxerDemoBuffer != nullptr) {
delete[] avMuxerDemoBuffer;
avMuxerDemoBuffer = nullptr;
}
}
void AVMuxerDemoBase::WriteAvTrackSample()
{
if (audioFile_ == nullptr || videoFile_ == nullptr) {
std::cout<<"AVMuxerDemoBase::WriteTrackSample audioFile_ or videoFile_ is nullptr!"<<std::endl;
return;
}
uint32_t dataSize = 0;
uint32_t flags = 0;
uint64_t audioPts = 0;
uint64_t videoPts = 0;
TrackSampleInfo info {0, 0, 0 ,0};
std::shared_ptr<std::ifstream> curFile = nullptr;
unsigned char *avMuxerDemoBuffer = nullptr;
uint32_t avMuxerDemoBufferSize = 0;
audioFile_->read((char *)&audioPts, sizeof(audioPts));
if (audioFile_->eof()) {
return;
}
videoFile_->read((char *)&videoPts, sizeof(videoPts));
if (videoFile_->eof()) {
return;
}
while (1) {
if (audioPts > videoPts) {
curFile = videoFile_;
info.trackIndex = videoTrackId_;
info.timeUs = videoPts;
} else {
curFile = audioFile_;
info.trackIndex = audioTrackId_;
info.timeUs = audioPts;
}
curFile->read((char *)&flags, sizeof(flags));
if (curFile->eof()) {
break;
}
curFile->read((char *)&dataSize, sizeof(dataSize));
if (curFile->eof()) {
break;
}
if (avMuxerDemoBuffer != nullptr && dataSize > avMuxerDemoBufferSize) {
delete [] avMuxerDemoBuffer;
avMuxerDemoBuffer = nullptr;
avMuxerDemoBufferSize = 0;
}
if (avMuxerDemoBuffer == nullptr) {
avMuxerDemoBuffer = new unsigned char[dataSize];
avMuxerDemoBufferSize = dataSize;
}
curFile->read((char *)avMuxerDemoBuffer, dataSize);
if(curFile->eof()) {
break;
}
info.size = dataSize;
info.flags = 0;
if (flags != 0) {
info.flags |= AVCODEC_BUFFER_FLAG_SYNC_FRAME;
}
if (DoWriteSampleBuffer((uint8_t*)avMuxerDemoBuffer, info) != 0) {
std::cout<<"DoWriteSampleBuffer failed!"<<std::endl;
}
if (curFile == audioFile_) {
audioFile_->read((char *)&audioPts, sizeof(audioPts));
if (audioFile_->eof()) {
break;
}
} else {
videoFile_->read((char *)&videoPts, sizeof(videoPts));
if (videoFile_->eof()) {
break;
}
}
}
if (avMuxerDemoBuffer != nullptr) {
delete [] avMuxerDemoBuffer;
avMuxerDemoBuffer = nullptr;
}
}
void AVMuxerDemoBase::WriteTrackSample()
{
if (audioFile_ != nullptr && videoFile_ != nullptr && audioTrackId_ >= 0 && videoTrackId_ >= 0) {
std::cout<<"AVMuxerDemoBase::WriteTrackSample write AUDIO and VIDEO sample"<<std::endl;
std::cout<<"audio trackId:"<<audioTrackId_<<" video trackId:"<<videoTrackId_<<std::endl;
WriteAvTrackSample();
} else if (audioFile_ != nullptr && audioTrackId_ >= 0) {
std::cout<<"AVMuxerDemoBase::WriteTrackSample write AUDIO sample"<<std::endl;
WriteSingleTrackSample(audioTrackId_, audioFile_);
} else if (videoFile_ != nullptr && videoTrackId_ >= 0) {
std::cout<<"AVMuxerDemoBase::WriteTrackSample write VIDEO sample"<<std::endl;
WriteSingleTrackSample(videoTrackId_, videoFile_);
} else {
std::cout<<"AVMuxerDemoBase::WriteTrackSample don't write AUDIO and VIDEO track!!"<<std::endl;
}
}
void AVMuxerDemoBase::MulThdWriteTrackSample(AVMuxerDemoBase *muxerBase, uint32_t trackId, std::shared_ptr<std::ifstream> file)
{
muxerBase->WriteSingleTrackSample(trackId, file);
}
void AVMuxerDemoBase::WriteCoverSample()
{
std::cout<<"AVMuxerDemoBase::WriteCoverSample"<<std::endl;
if (coverFile_ == nullptr) {
std::cout<<"AVMuxerDemoBase::WriteCoverSample coverFile_ is nullptr!"<<std::endl;
return;
}
TrackSampleInfo info {coverTrackId_, 0, 0 ,0};
coverFile_->seekg(0, std::ios::end);
info.size = coverFile_->tellg();
coverFile_->seekg(0, std::ios::beg);
if (info.size <= 0) {
std::cout<<"AVMuxerDemoBase::WriteCoverSample coverFile_ size is 0!"<<std::endl;
return;
}
unsigned char *avMuxerDemoBuffer = new unsigned char[info.size];
coverFile_->read((char *)avMuxerDemoBuffer, info.size);
if (DoWriteSampleBuffer((uint8_t*)avMuxerDemoBuffer, info) != AVCS_ERR_OK) {
delete [] avMuxerDemoBuffer;
std::cout<<"WriteCoverSample error"<<std::endl;
return;
}
delete [] avMuxerDemoBuffer;
}
int AVMuxerDemoBase::AddVideoTrack(VideoTrackParam *param)
{
if (param == nullptr) {
std::cout<<"AVMuxerDemoBase::AddVideoTrack video is not select!"<<std::endl;
return -1;
}
MediaDescription videoParams;
videoParams.PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, param->mimeType);
videoParams.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, param->width);
videoParams.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, param->height);
int extSize = 0;
char buffer[100] {0};
// fread(&extSize, sizeof(extSize), 1, g_avBinStrNewFd);
videoFile_->read((char*)&extSize, sizeof(extSize));
if (extSize > 0 && extSize < 100) {
// fread(buffer, extSize, 1, g_avBinStrNewFd);
videoFile_->read((char*)buffer, extSize);
videoParams.PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, (uint8_t *)buffer, extSize);
} else {
std::cout<<"AVMuxerDemoBase::AddVideoTrack DoAddTrack failed!"<<std::endl;
}
if (DoAddTrack(videoTrackId_, videoParams) != AVCS_ERR_OK) {
return -1;
}
std::cout << "AVMuxerDemoBase::AddVideoTrack video trackId is: " << videoTrackId_ << std::endl;
return 0;
}
int AVMuxerDemoBase::AddAudioTrack(AudioTrackParam *param)
{
if (param == nullptr) {
std::cout<<"AVMuxerDemoBase::AddAudioTrack audio is not select!"<<std::endl;
return -1;
}
MediaDescription audioParams;
audioParams.PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, param->mimeType);
audioParams.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, param->sampleRate);
audioParams.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, param->channels);
int extSize = 0;
char buffer[100] {0};
audioFile_->read((char*)&extSize, sizeof(extSize));
if (extSize > 0 && extSize < 100) {
audioFile_->read((char*)buffer, extSize);
audioParams.PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, (uint8_t *)buffer, extSize);
} else {
std::cout<<"AVMuxerDemoBase::AddAudioTrack error extSize:"<<extSize<<std::endl;
}
if (DoAddTrack(audioTrackId_, audioParams) != 0) {
std::cout<<"AVMuxerDemoBase::AddAudioTrack DoAddTrack failed!"<<std::endl;
return -1;
}
std::cout << "AVMuxerDemoBase::AddAudioTrack audio trackId is: " << audioTrackId_ << std::endl;
return 0;
}
int AVMuxerDemoBase::AddCoverTrack(VideoTrackParam *param)
{
if (param == nullptr) {
std::cout<<"AVMuxerDemoBase::AddCoverTrack cover is not select!"<<std::endl;
return -1;
}
MediaDescription coverParams;
coverParams.PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, param->mimeType);
coverParams.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, param->width);
coverParams.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, param->height);
if (DoAddTrack(coverTrackId_, coverParams) != AVCS_ERR_OK) {
return -1;
}
std::cout << "AVMuxerDemoBase::AddCoverTrack video trackId is: " << coverTrackId_ << std::endl;
return 0;
}
} // Media
} // OHOS

View File

@ -0,0 +1,65 @@
/*
* 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.
*/
#ifndef AVMUXER_DEMO_BASE
#define AVMUXER_DEMO_BASE
#include <string>
#include "av_common.h"
#include "media_description.h"
#include "avmuxer_demo_common.h"
namespace OHOS {
namespace Media {
class AVMuxerDemoBase {
public:
AVMuxerDemoBase();
virtual ~AVMuxerDemoBase() = default;
void RunCase();
void RunMultiThreadCase();
protected:
virtual void DoRunMuxer() = 0;
virtual void DoRunMultiThreadCase()= 0;
virtual int DoWriteSampleBuffer(uint8_t *sampleBuffer, TrackSampleInfo &info) = 0;
virtual int DoAddTrack(int32_t &trackIndex, MediaDescription &trackDesc) = 0;
int AddVideoTrack(VideoTrackParam *param);
int AddAudioTrack(AudioTrackParam *param);
int AddCoverTrack(VideoTrackParam *param);
void WriteTrackSample();
void WriteAvTrackSample();
void WriteSingleTrackSample(uint32_t trackId, std::shared_ptr<std::ifstream> file);
void WriteCoverSample();
int SelectMode();
int SelectModeAndOpenFile();
void Reset();
static void MulThdWriteTrackSample(AVMuxerDemoBase *muxerBase, uint32_t trackId, std::shared_ptr<std::ifstream> file);
int32_t videoTrackId_ {-1};
int32_t audioTrackId_ {-1};
int32_t coverTrackId_ {-1};
std::shared_ptr<std::ifstream> audioFile_ {nullptr};
std::shared_ptr<std::ifstream> videoFile_ {nullptr};
std::shared_ptr<std::ifstream> coverFile_ {nullptr};
AudioTrackParam *audioParams_ {nullptr};
VideoTrackParam *videoParams_ {nullptr};
VideoTrackParam *coverParams_ {nullptr};
std::string videoType_ = std::string("");
std::string audioType_ = std::string("");
std::string coverType_ = std::string("");
std::string format_ = std::string("");
int32_t outFd_ {-1};
OutputFormat outputFormat_ {OUTPUT_FORMAT_MPEG_4};
};
} // Media
} // OHOS
#endif

View File

@ -0,0 +1,68 @@
/*
* 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 "avmuxer_demo_common.h"
struct AudioTrackParam g_audioMpegPar = {
.fileName = "mpeg_44100_2.bin",
.mimeType = "audio/mpeg",
.sampleRate = 44100,
.channels = 2,
};
struct AudioTrackParam g_audioAacPar = {
.fileName = "aac_44100_2.bin",
.mimeType = "audio/mp4a-latm",
.sampleRate = 44100,
.channels = 2,
};
struct VideoTrackParam g_videoH264Par = {
.fileName = "h264_640_360.bin",
.mimeType = "video/avc",
.width = 640,
.height = 360,
};
struct VideoTrackParam g_videoMpeg4Par = {
.fileName = "mpeg4_720_480.bin",
.mimeType = "video/mp4v-es",
.width = 720,
.height = 480,
};
struct VideoTrackParam g_jpegCoverPar = {
.fileName = "greatwall.jpg",
.mimeType = "image/jpeg",
.width = 352,
.height = 288,
};
struct VideoTrackParam g_pngCoverPar = {
.fileName = "greatwall.png",
.mimeType = "image/png",
.width = 352,
.height = 288,
};
struct VideoTrackParam g_bmpCoverPar = {
.fileName = "greatwall.bmp",
.mimeType = "image/bmp",
.width = 352,
.height = 288,
};
const char *RUN_NORMAL = "normal";
const char *RUN_MUL_THREAD = "multhrd";

View File

@ -0,0 +1,42 @@
/*
* 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.
*/
#ifndef AVMUXER_DEMO_COMMON_H
#define AVMUXER_DEMO_COMMON_H
// only for demo
typedef struct AudioTrackParam {
const char *fileName;
const char *mimeType;
int sampleRate;
int channels;
} AudioTrackParam;
typedef struct VideoTrackParam {
const char *fileName;
const char *mimeType;
int width;
int height;
} VideoTrackParam;
typedef struct FdListStr {
int start[0];
int outputFd;
int inAudioFd;
int inVideoFd;
int inCoverFd;
} FdListStr;
#endif

View File

@ -0,0 +1,139 @@
/*
* 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 "avmuxer_engine_demo.h"
#include <iostream>
#include <fstream>
#include <cstdio>
#include <unistd.h>
#include <fcntl.h>
#include <thread>
#include <vector>
#include "securec.h"
#include "avcodec_errors.h"
#include "avsharedmemorybase.h"
namespace OHOS {
namespace Media {
namespace {
extern "C" {
extern char *RUN_NORMAL;
extern char *RUN_MUL_THREAD;
}
}
int AVMuxerEngineDemo::DoWriteSampleBuffer(uint8_t *sampleBuffer, TrackSampleInfo &info)
{
std::shared_ptr<AVSharedMemoryBase> sharedSampleBuffer =
std::make_shared<AVSharedMemoryBase>(info.size, AVSharedMemory::FLAGS_READ_ONLY, "sampleBuffer");
int32_t ret = sharedSampleBuffer->Init();
if (ret != AVCS_ERR_OK) {
std::cout<<"AVMuxerEngineDemo::DoWriteSampleBuffer shared memory Init failed!"<<std::endl;
}
errno_t rc = memcpy_s(sharedSampleBuffer->GetBase(), sharedSampleBuffer->GetSize(), sampleBuffer, info.size);
if (rc != EOK) {
std::cout<<"AVMuxerEngineDemo::DoWriteSampleBuffer memcpy_s failed!"<<std::endl;
}
if (avmuxer_ != nullptr &&
avmuxer_->WriteSampleBuffer(sharedSampleBuffer, info) == AVCS_ERR_OK) {
return 0;
}
return -1;
}
int AVMuxerEngineDemo::DoAddTrack(int32_t &trackIndex, MediaDescription &trackDesc)
{
int ret;
if ((ret = avmuxer_->AddTrack(trackIndex, trackDesc)) != AVCS_ERR_OK) {
std::cout<<"AVMuxerDemo::DoAddTrack failed! ret:"<<ret<<std::endl;
return -1;
}
return 0;
}
void AVMuxerEngineDemo::DoRunMuxer(const std::string &runMode)
{
std::string outFileName = "engine_mux_" + runMode + "_" + audioType_ + "_" + videoType_ + "_" + coverType_ + "." + format_;
outFd_ = open(outFileName.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
if (outFd_ < 0) {
std::cout << "Open file failed! filePath is: " << outFileName << std::endl;
return;
}
std::cout<<"==== open success! =====\noutputFileName: "<<outFileName<<"\n============"<<std::endl;
avmuxer_ = IMuxerEngineFactory::CreateMuxerEngine(-1, -1, outFd_, outputFormat_);
if (avmuxer_ == nullptr) {
std::cout << "avmuxer_ is null" << std::endl;
return;
}
std::cout << "create muxer success " << avmuxer_ << std::endl;
if (avmuxer_->SetLocation(10, 10) != AVCS_ERR_OK
|| avmuxer_->SetRotation(0) != AVCS_ERR_OK) {
std::cout<<"set failed!"<<std::endl;
return;
}
AddAudioTrack(audioParams_);
AddVideoTrack(videoParams_);
AddCoverTrack(coverParams_);
std::cout << "add track success" << std::endl;
if (avmuxer_->Start() != AVCS_ERR_OK) {
return;
}
std::cout << "start muxer success" << std::endl;
if (coverParams_ != nullptr) {
WriteCoverSample();
}
std::cout<<"AVMuxerDemo::DoRunMuxer runMode is : "<<runMode<<std::endl;
if (runMode.compare(RUN_NORMAL) == 0) {
WriteTrackSample();
} else if (runMode.compare(RUN_MUL_THREAD) == 0) {
std::vector<std::thread> vecThread;
vecThread.emplace_back(MulThdWriteTrackSample, this, audioTrackId_, audioFile_);
vecThread.emplace_back(MulThdWriteTrackSample, this, videoTrackId_, videoFile_);
for (uint32_t i = 0; i < vecThread.size(); ++i) {
vecThread[i].join();
}
}
std::cout << "write muxer success" << std::endl;
if (avmuxer_->Stop() != AVCS_ERR_OK) {
return;
}
std::cout << "stop muxer success" << std::endl;
}
void AVMuxerEngineDemo::DoRunMuxer()
{
DoRunMuxer(std::string(RUN_NORMAL));
}
void AVMuxerEngineDemo::DoRunMultiThreadCase()
{
DoRunMuxer(std::string(RUN_MUL_THREAD));
}
} // namespace Media
} // namespace OHOS

View File

@ -0,0 +1,38 @@
/*
* 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.
*/
#ifndef AVMUXER_ENGINE_DEMO_H
#define AVMUXER_ENGINE_DEMO_H
#include "avmuxer_demo_base.h"
#include "i_muxer_engine.h"
namespace OHOS {
namespace Media {
class AVMuxerEngineDemo /*: public NoCopyable*/ : public AVMuxerDemoBase {
public:
AVMuxerEngineDemo() = default;
~AVMuxerEngineDemo() = default;
private:
void DoRunMuxer() override;
int DoWriteSampleBuffer(uint8_t *sampleBuffer, TrackSampleInfo &info) override;
int DoAddTrack(int32_t &trackIndex, MediaDescription &trackDesc) override;
void DoRunMultiThreadCase() override;
void DoRunMuxer(const std::string &runMode);
std::shared_ptr<IMuxerEngine> avmuxer_;
};
} // namespace Media
} // namespace OHOS
#endif // AVMUXER_DEMO_H

View File

@ -0,0 +1,153 @@
/*
* 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 "avmuxer_ffmpeg_demo.h"
#include <dlfcn.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
#include <fstream>
namespace {
const char *FFMPEG_REGISTER_FUNC_NAME = "register_FFmpegMuxer";
const char *FFMPEG_UNREGISTER_FUNC_NAME = "unregister_FFmpegMuxer";
const char *FFMPEG_LIB_PATH = "/system/lib/media/av_codec_plugins/libav_codec_plugin_FFmpegMuxer.z.so";
}
namespace OHOS {
namespace Media {
namespace Plugin {
Status AVMuxerFFmpegDemo::FfmpegRegister::AddPlugin(const PluginDefBase& def)
{
auto& tempDef = (MuxerPluginDef&)def;
std::cout<<"find plugin apiVersion:"<<tempDef.apiVersion;
std::cout<<" |pluginType:"<<(int32_t)tempDef.pluginType;
std::cout<<" |name:"<<tempDef.name;
std::cout<<" |description:"<<tempDef.description;
std::cout<<" |rank:"<<tempDef.rank;
std::cout<<" |sniffer:"<<(void*)tempDef.sniffer;
std::cout<<" |creator:"<<(void*)tempDef.creator;
std::cout<<std::endl;
plugins.push_back(tempDef);
return Status::NO_ERROR;
}
AVMuxerFFmpegDemo::AVMuxerFFmpegDemo()
{
register_ = std::make_shared<FfmpegRegister>();
}
int AVMuxerFFmpegDemo::DoAddTrack(int32_t &trackIndex, MediaDescription &param)
{
int32_t tempTrackId = 0;
ffmpegMuxer_->AddTrack(tempTrackId, param);
if (tempTrackId < 0) {
std::cout<<"AVMuxerFFmpegDemo::DoAddTrack failed! trackId:"<<tempTrackId<<std::endl;
return -1;
}
trackIndex = tempTrackId;
return 0;
}
void AVMuxerFFmpegDemo::DoRunMuxer()
{
GetFfmpegRegister();
if (register_->plugins.size() <= 0) {
std::cout<<"regist muxers failed!"<<std::endl;
return;
}
int32_t maxProb = 0;
MuxerPluginDef pluginDef{};
for (auto& plugin : register_->plugins) {
if (plugin.pluginType == PluginType::MUXER) {
auto prob = plugin.sniffer(plugin.name, outputFormat_);
if (prob > maxProb) {
maxProb = prob;
pluginDef = plugin;
}
}
}
if (pluginDef.creator == nullptr) {
std::cout<<"no plugins matching output format - "<< outputFormat_ <<std::endl;
return;
}
std::string outFileName = "ffmpeg_mux_" + audioType_ + "_" + videoType_ + "_" + coverType_ + "." + format_;
outFd_ = open(outFileName.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (outFd_ < 0) {
std::cout<<"create muxer output file failed! fd:"<<outFd_<<std::endl;
return;
}
std::cout<<"==== open success! =====\noutputFileName: "<<outFileName<<"\n============"<<std::endl;
ffmpegMuxer_ = pluginDef.creator(pluginDef.name, outFd_);
if (ffmpegMuxer_ == nullptr) {
std::cout<<"ffmpegMuxer create failed!"<<std::endl;
return;
}
ffmpegMuxer_->SetLocation(10, 10);
ffmpegMuxer_->SetRotation(90);
AddAudioTrack(audioParams_);
AddVideoTrack(videoParams_);
ffmpegMuxer_->Start();
WriteTrackSample();
ffmpegMuxer_->Stop();
}
void AVMuxerFFmpegDemo::DoRunMultiThreadCase()
{
std::cout<<"ffmpeg plugin demo is not support multi-thread write!"<<std::endl;
return;
}
int AVMuxerFFmpegDemo::DoWriteSampleBuffer(uint8_t *sampleBuffer, TrackSampleInfo &info)
{
if(ffmpegMuxer_ != nullptr &&
ffmpegMuxer_->WriteSampleBuffer(sampleBuffer, info) == Status::NO_ERROR) {
return 0;
}
return -1;
}
int AVMuxerFFmpegDemo::GetFfmpegRegister()
{
dlHandle_ = ::dlopen(FFMPEG_LIB_PATH, RTLD_NOW | RTLD_LOCAL);
if (dlHandle_ == nullptr) {
std::cout<<"AVMuxerFFmpegDemo::GetFfmpegRegister dlHandle_ is nullptr!"<<std::endl;
return -1;
}
registerFunc_ = (RegisterFunc)(::dlsym(dlHandle_, FFMPEG_REGISTER_FUNC_NAME));
unregisterFunc_ = (UnregisterFunc)(::dlsym(dlHandle_, FFMPEG_UNREGISTER_FUNC_NAME));
if (registerFunc_ == nullptr || unregisterFunc_ == nullptr) {
std::cout<<"get dl function failed! registerFunc_:"<<(void*)registerFunc_;
return -1;
}
if ((int32_t)registerFunc_(register_) != 0) {
std::cout<<"ffmpeg register failed!"<<std::endl;
return -1;
}
return 0;
}
} // Plugin
} // namespace Media
} // namespace OHOS

View File

@ -0,0 +1,58 @@
/*
* 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.
*/
#ifndef AVMUXER_FFMPEG_DEMO_H
#define AVMUXER_FFMPEG_DEMO_H
#include <vector>
#include "avmuxer.h"
#include "muxer_plugin.h"
#include "avmuxer_demo_base.h"
#include "plugin_definition.h"
namespace OHOS {
namespace Media {
namespace Plugin {
class AVMuxerFFmpegDemo /*: public NoCopyable*/ : public AVMuxerDemoBase {
public:
AVMuxerFFmpegDemo();
~AVMuxerFFmpegDemo() = default;
private:
struct FfmpegRegister : PackageRegister {
Status AddPlugin(const PluginDefBase& def) override;
Status AddPackage(const PackageDef& def) override {
(void)def;
return Status::NO_ERROR;
}
std::vector<MuxerPluginDef> plugins;
};
void DoRunMuxer() override;
int GetFfmpegRegister();
int DoWriteSampleBuffer(uint8_t *sampleBuffer, TrackSampleInfo &info) override;
int DoAddTrack(int32_t &trackIndex, MediaDescription &trackDesc) override;
void DoRunMultiThreadCase() override;
std::shared_ptr<MuxerPlugin> ffmpegMuxer_ {nullptr};
std::shared_ptr<FfmpegRegister> register_ {nullptr};
void *dlHandle_ {nullptr};
RegisterFunc registerFunc_ {nullptr};
UnregisterFunc unregisterFunc_ {nullptr};
};
} // Plugin
} // namespace Media
} // namespace OHOS
#endif // AVMUXER_FFMPEG_DEMO_H

View File

@ -0,0 +1,665 @@
/*
* 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 <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include "securec.h"
#include "native_avcodec_base.h"
#include "native_averrors.h"
#include "native_avformat.h"
#include "native_avmuxer.h"
#include "avmuxer_demo_common.h"
#define NORMAL 0
#define THREAD 1
struct WriteTrackSampleParam {
OH_AVMuxer *muxer;
int trackId;
int fd;
};
struct MuxerParam {
int outputFormat;
char outputFormatType[20];
int runMode;
char runModeType[20];
AudioTrackParam *audioParams;
char audioType[20];
VideoTrackParam *videoParams;
char videoType[20];
VideoTrackParam *coverParams;
char coverType[20];
};
extern char *RUN_NORMAL;
extern char *RUN_MUL_THREAD;
extern AudioTrackParam g_audioMpegPar;
extern AudioTrackParam g_audioAacPar;
extern VideoTrackParam g_videoH264Par;
extern VideoTrackParam g_videoMpeg4Par;
extern VideoTrackParam g_jpegCoverPar;
extern VideoTrackParam g_pngCoverPar;
extern VideoTrackParam g_bmpCoverPar;
static struct MuxerParam g_muxerParam = {
.outputFormat = AV_OUTPUT_FORMAT_UNKNOWN,
.outputFormatType = "",
.runMode = NORMAL,
.runModeType = "",
.audioParams = NULL,
.audioType = "",
.videoParams = NULL,
.videoType = "",
.coverParams = NULL,
.coverType = "",
};
int AddTrackAudio(OH_AVMuxer *muxer, const AudioTrackParam *param, int fdInput)
{
if (fdInput < 0) {
printf("unselect audio, fd is %d\n", fdInput);
return -1;
}
OH_AVFormat *formatAudio = OH_AVFormat_Create();
if (formatAudio == NULL) {
printf("audio format failed!\n");
return AV_ERR_NO_MEMORY;
}
int extraSize = 0;
unsigned char buffer[100] = {0};
read(fdInput, (void*)&extraSize, sizeof(extraSize));
if (extraSize <= 100 && extraSize > 0) {
read(fdInput, buffer, extraSize);
OH_AVFormat_SetBuffer(formatAudio, OH_MD_KEY_CODEC_CONFIG, buffer, extraSize);
}
printf("AddTrackAudio audio metadata size: %d\n", extraSize);
OH_AVFormat_SetStringValue(formatAudio, OH_MD_KEY_CODEC_MIME, param->mimeType);
OH_AVFormat_SetIntValue(formatAudio, OH_MD_KEY_AUD_SAMPLE_RATE, param->sampleRate);
OH_AVFormat_SetIntValue(formatAudio, OH_MD_KEY_AUD_CHANNEL_COUNT, param->channels);
int trackIndex = -1;
int ret = OH_AVMuxer_AddTrack(muxer, &trackIndex, formatAudio);
OH_AVFormat_Destroy(formatAudio);
if (ret != AV_ERR_OK) {
printf("AddTrackAudio failed! mime: %s\n", param->mimeType);
return -1;
}
printf("AddTrackAudio success! trackIndex: %d\n", trackIndex);
return trackIndex;
}
int AddTrackVideo(OH_AVMuxer *muxer, const VideoTrackParam *param, int fdInput)
{
if (fdInput < 0) {
printf("unselect video, fd is %d\n", fdInput);
return -1;
}
OH_AVFormat *formatVideo = OH_AVFormat_Create();
if (formatVideo == NULL) {
printf("video format failed!\n");
return AV_ERR_NO_MEMORY;
}
int extraSize = 0;
unsigned char buffer[100] = {0};
read(fdInput, (void*)&extraSize, sizeof(extraSize));
if (extraSize <= 100 && extraSize > 0) {
read(fdInput, buffer, extraSize);
OH_AVFormat_SetBuffer(formatVideo, OH_MD_KEY_CODEC_CONFIG, buffer, extraSize);
}
printf("AddTrackVideo video metadata size: %d\n", extraSize);
OH_AVFormat_SetStringValue(formatVideo, OH_MD_KEY_CODEC_MIME, param->mimeType);
OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_WIDTH, param->width);
OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_HEIGHT, param->height);
int trackIndex = -1;
int ret = OH_AVMuxer_AddTrack(muxer, &trackIndex, formatVideo);
OH_AVFormat_Destroy(formatVideo);
if (ret != AV_ERR_OK) {
printf("AddTrackVideo failed! mime: %s\n", param->mimeType);
return -1;
}
printf("AddTrackVideo success! trackIndex: %d\n", trackIndex);
return trackIndex;
}
int AddTrackCover(OH_AVMuxer *muxer, const VideoTrackParam *param, int fdInput)
{
if (fdInput < 0) {
printf("unselect cover, fd is %d\n", fdInput);
return -1;
}
OH_AVFormat *formatCover = OH_AVFormat_Create();
if (formatCover == NULL) {
printf("cover format failed!\n");
return AV_ERR_NO_MEMORY;
}
OH_AVFormat_SetStringValue(formatCover, OH_MD_KEY_CODEC_MIME, param->mimeType);
OH_AVFormat_SetIntValue(formatCover, OH_MD_KEY_WIDTH, param->width);
OH_AVFormat_SetIntValue(formatCover, OH_MD_KEY_HEIGHT, param->height);
int trackIndex = -1;
int ret = OH_AVMuxer_AddTrack(muxer, &trackIndex, formatCover);
OH_AVFormat_Destroy(formatCover);
if (ret != AV_ERR_OK) {
printf("AddTrackCover failed! mime: %s\n", param->mimeType);
return -1;
}
printf("AddTrackCover success! trackIndex: %d\n", trackIndex);
return trackIndex;
}
void WriteSingleTrackSample(OH_AVMuxer *muxer, int trackId, int fd)
{
if (muxer == NULL || fd < 0 || trackId < 0) {
printf("WriteSingleTrackSample muxer is null or fd < 0, fd:%d\n", fd);
return;
}
int ret = 0;
int dataSize = 0;
int flags = 0;
unsigned char *avMuxerDemoBuffer = NULL;
int avMuxerDemoBufferSize = 0;
OH_AVCodecBufferAttr info;
memset_s(&info, sizeof(info), 0, sizeof(info));
while (1) {
ret = read(fd, (void*)&info.pts, sizeof(info.pts));
if (ret <= 0) {
break;
}
ret = read(fd, (void*)&flags, sizeof(flags));
if (ret <= 0) {
break;
}
// read frame buffer
ret = read(fd, (void*)&dataSize, sizeof(dataSize));
if (ret <= 0 || dataSize < 0) {
break;
}
if (avMuxerDemoBuffer != NULL && dataSize > avMuxerDemoBufferSize) {
free(avMuxerDemoBuffer);
avMuxerDemoBufferSize = 0;
avMuxerDemoBuffer = NULL;
}
if (avMuxerDemoBuffer == NULL) {
avMuxerDemoBuffer = malloc(dataSize);
avMuxerDemoBufferSize = dataSize;
if (avMuxerDemoBuffer == NULL) {
printf("error malloc memory! %d\n", dataSize);
break;
}
}
ret = read(fd, (void*)avMuxerDemoBuffer, dataSize);
if (ret <= 0) {
break;
}
info.size = dataSize;
info.flags = 0;
if (flags != 0) {
info.flags |= AVCODEC_BUFFER_FLAGS_SYNC_FRAME;
}
if (OH_AVMuxer_WriteSampleBuffer(muxer, trackId, avMuxerDemoBuffer, info) != AV_ERR_OK) {
printf("OH_AVMuxer_WriteSampleBuffer error!\n");
break;
}
}
if (avMuxerDemoBuffer != NULL) {
free(avMuxerDemoBuffer);
}
}
void *ThreadWriteTrackSample(void *param)
{
struct WriteTrackSampleParam *wrTrackParam = (struct WriteTrackSampleParam *)param;
WriteSingleTrackSample(wrTrackParam->muxer, wrTrackParam->trackId, wrTrackParam->fd);
return NULL;
}
void WriteTrackSample(OH_AVMuxer *muxer, int audioTrackIndex, int videoTrackIndex, FdListStr *fdStr)
{
if (fdStr == NULL || fdStr->inAudioFd < 0 || fdStr->inVideoFd < 0) {
printf("WriteTrackSample start failed!\n");
return;
}
printf("WriteTrackSample\n");
int dataSize = 0;
int ret = 0;
int trackId = 0;
int curFd = 0;
int flags = 0;
int64_t audioPts = 0;
int64_t videoPts = 0;
OH_AVCodecBufferAttr info;
memset_s(&info, sizeof(info), 0, sizeof(info));
unsigned char *avMuxerDemoBuffer = NULL;
int avMuxerDemoBufferSize = 0;
ret = read(fdStr->inAudioFd, (void*)&audioPts, sizeof(audioPts));
if (ret <= 0) {
return;
}
ret = read(fdStr->inVideoFd, (void*)&videoPts, sizeof(videoPts));
if (ret <= 0) {
return;
}
while (1) {
if (audioPts > videoPts) { // write video
info.pts = videoPts;
trackId = videoTrackIndex;
curFd = fdStr->inVideoFd;
} else { // write audio
info.pts = audioPts;
trackId = audioTrackIndex;
curFd = fdStr->inAudioFd;
}
// read flags
ret = read(curFd, (void*)&flags, sizeof(flags));
if (ret <= 0) {
break;
}
info.flags = 0;
if (flags != 0) {
info.flags |= AVCODEC_BUFFER_FLAGS_SYNC_FRAME;
}
// read frame buffer
ret = read(curFd, (void*)&dataSize, sizeof(dataSize));
if (ret <= 0 || dataSize < 0) {
break;
}
if (avMuxerDemoBuffer != NULL && dataSize > avMuxerDemoBufferSize) {
free(avMuxerDemoBuffer);
avMuxerDemoBufferSize = 0;
avMuxerDemoBuffer = NULL;
}
if (avMuxerDemoBuffer == NULL) {
avMuxerDemoBuffer = malloc(dataSize);
avMuxerDemoBufferSize = dataSize;
if (avMuxerDemoBuffer == NULL) {
printf("error malloc memory! %d\n", dataSize);
break;
}
}
ret = read(curFd, (void*)avMuxerDemoBuffer, dataSize);
if (ret <= 0) {
break;
}
info.size = dataSize;
if (OH_AVMuxer_WriteSampleBuffer(muxer, trackId, avMuxerDemoBuffer, info) != AV_ERR_OK) {
printf("OH_AVMuxer_WriteSampleBuffer error!\n");
break;
}
if (curFd == fdStr->inVideoFd) {
ret = read(fdStr->inVideoFd, (void*)&videoPts, sizeof(videoPts));
if (ret <= 0) {
break;
}
} else {
ret = read(fdStr->inAudioFd, (void*)&audioPts, sizeof(audioPts));
if (ret <= 0) {
break;
}
}
}
if (avMuxerDemoBuffer != NULL) {
free(avMuxerDemoBuffer);
}
}
void WriteTrackCover(OH_AVMuxer *muxer, int coverTrackIndex, int fdInput)
{
printf("WriteTrackCover\n");
OH_AVCodecBufferAttr info;
memset_s(&info, sizeof(info), 0, sizeof(info));
struct stat fileStat;
fstat(fdInput, &fileStat);
info.size = fileStat.st_size;
unsigned char *avMuxerDemoBuffer = malloc(info.size);
if (avMuxerDemoBuffer == NULL) {
printf("malloc memory error! size: %d \n", info.size);
return;
}
int ret = read(fdInput, avMuxerDemoBuffer, info.size);
if (ret <= 0) {
free(avMuxerDemoBuffer);
return;
}
if (OH_AVMuxer_WriteSampleBuffer(muxer, coverTrackIndex, avMuxerDemoBuffer, info) != AV_ERR_OK) {
free(avMuxerDemoBuffer);
printf("OH_AVMuxer_WriteSampleBuffer error!\n");
return;
}
free(avMuxerDemoBuffer);
}
int GetInputNum(int defaultNum)
{
int num = defaultNum;
num = getchar();
if (num == '\n') { // default
num = defaultNum;
} else {
ungetc(num, stdin);
scanf("%d", &num);
fflush(stdin);
}
return num;
}
void NativeSelectMuxerType()
{
int num;
printf("\nplese select muxer type : 0.mp4 1.m4a\n");
num = GetInputNum(0);
switch (num)
{
case 0:
g_muxerParam.outputFormat = AV_OUTPUT_FORMAT_MPEG_4;
snprintf(g_muxerParam.outputFormatType, sizeof(g_muxerParam.outputFormatType), "%s", "mp4");
break;
case 1:
g_muxerParam.outputFormat = AV_OUTPUT_FORMAT_M4A;
snprintf(g_muxerParam.outputFormatType, sizeof(g_muxerParam.outputFormatType), "%s", "m4a");
break;
default:
g_muxerParam.outputFormat = AV_OUTPUT_FORMAT_MPEG_4;
snprintf(g_muxerParam.outputFormatType, sizeof(g_muxerParam.outputFormatType), "%s", "mp4");
break;
}
printf("select mode:%d\n", num);
}
void NativeSelectRunMode()
{
int num;
printf("\nplese select audio vide wrtie mode:\n");
printf("0. audio video write in sample thread\n");
printf("1. audio video write in different thread\n");
num = GetInputNum(0);
switch (num)
{
case 0:
g_muxerParam.runMode = NORMAL;
snprintf(g_muxerParam.runModeType, sizeof(g_muxerParam.runModeType), "%s", RUN_NORMAL);
break;
case 1:
g_muxerParam.runMode = THREAD;
snprintf(g_muxerParam.runModeType, sizeof(g_muxerParam.runModeType), "%s", RUN_MUL_THREAD);
break;
default:
g_muxerParam.runMode = NORMAL;
snprintf(g_muxerParam.runModeType, sizeof(g_muxerParam.runModeType), "%s", RUN_NORMAL);
break;
}
printf("select mode:%d\n", num);
}
void NativeSelectAudio()
{
int num;
printf("\nplese select audio mode: 0.noAudio 1.aac 2.mpeg\n");
num = GetInputNum(1);
switch (num)
{
case 1:
g_muxerParam.audioParams = &g_audioAacPar;
snprintf(g_muxerParam.audioType, sizeof(g_muxerParam.audioType), "%s", "aac");
break;
case 2:
g_muxerParam.audioParams = &g_audioMpegPar;
snprintf(g_muxerParam.audioType, sizeof(g_muxerParam.audioType), "%s", "mpeg");
break;
default:
g_muxerParam.audioParams = NULL;
snprintf(g_muxerParam.audioType, sizeof(g_muxerParam.audioType), "%s", "noAudio");
break;
}
printf("select mode:%d\n", num);
}
void NativeSelectVideo()
{
int num;
printf("\nplese select video mode: 0.noVideo 1.h264 2.mpeg4\n");
num = GetInputNum(1);
switch (num)
{
case 1:
g_muxerParam.videoParams = &g_videoH264Par;
snprintf(g_muxerParam.videoType, sizeof(g_muxerParam.videoType), "%s", "h264");
break;
case 2:
g_muxerParam.videoParams = &g_videoMpeg4Par;
snprintf(g_muxerParam.videoType, sizeof(g_muxerParam.videoType), "%s", "mpeg4");
break;
default:
g_muxerParam.videoParams = NULL;
snprintf(g_muxerParam.videoType, sizeof(g_muxerParam.videoType), "%s", "noVideo");
break;
}
printf("select mode:%d\n", num);
}
void NativeSelectCover()
{
int num;
printf("\nplese select cover mode: 0.noCover 1.jpg 2.png 3.bmp\n");
num = GetInputNum(1);
switch (num)
{
case 1:
g_muxerParam.coverParams = &g_jpegCoverPar;
snprintf(g_muxerParam.coverType, sizeof(g_muxerParam.coverType), "%s", "jpg");
break;
case 2:
g_muxerParam.coverParams = &g_pngCoverPar;
snprintf(g_muxerParam.coverType, sizeof(g_muxerParam.coverType), "%s", "png");
break;
case 3:
g_muxerParam.coverParams = &g_bmpCoverPar;
snprintf(g_muxerParam.coverType, sizeof(g_muxerParam.coverType), "%s", "bmp");
break;
default:
g_muxerParam.coverParams = NULL;
snprintf(g_muxerParam.coverType, sizeof(g_muxerParam.coverType), "%s", "noCover");
break;
}
printf("select mode:%d\n", num);
}
void NativeSelectMode()
{
if (g_muxerParam.outputFormat != AV_OUTPUT_FORMAT_UNKNOWN) {
return;
}
NativeSelectMuxerType();
NativeSelectRunMode();
NativeSelectAudio();
NativeSelectVideo();
NativeSelectCover();
}
int OpenAllInputFile(FdListStr *fdStr)
{
if (!fdStr) {
printf("fdStr is null!\n");
return -1;
}
if (g_muxerParam.audioParams) {
fdStr->inAudioFd = open(g_muxerParam.audioParams->fileName, O_RDONLY);
if (fdStr->inAudioFd < 0) {
printf("open %s failed!!\n", g_muxerParam.audioParams->fileName);
} else {
printf("open file %s success, -fd:%d, -flags %x\n", g_muxerParam.audioParams->fileName,
fdStr->inAudioFd, fcntl(fdStr->inAudioFd, F_GETFL, 0));
}
}
if (g_muxerParam.videoParams) {
fdStr->inVideoFd = open(g_muxerParam.videoParams->fileName, O_RDONLY);
if (fdStr->inVideoFd < 0) {
printf("open %s failed!!\n", g_muxerParam.videoParams->fileName);
} else {
printf("open file %s success, -fd:%d, -flags %x\n", g_muxerParam.videoParams->fileName,
fdStr->inVideoFd, fcntl(fdStr->inVideoFd, F_GETFL, 0));
}
}
if (g_muxerParam.coverParams) {
fdStr->inCoverFd = open(g_muxerParam.coverParams->fileName, O_RDONLY);
if (fdStr->inCoverFd < 0) {
printf("open %s failed!!\n", g_muxerParam.coverParams->fileName);
} else {
printf("open file %s success, -fd:%d, -flags %x\n", g_muxerParam.coverParams->fileName,
fdStr->inCoverFd, fcntl(fdStr->inCoverFd, F_GETFL, 0));
}
}
return 0;
}
int DoRunMuxer(FdListStr *fdStr, OH_AVMuxer *muxer)
{
if (fdStr == NULL || muxer == NULL) {
printf("fdStr or muxer is null!\n");
return -1;
}
if (OH_AVMuxer_SetLocation(muxer, 10, 10) != AV_ERR_OK
|| OH_AVMuxer_SetRotation(muxer, 0) != AV_ERR_OK ) {
printf("set failed!\n");
return -1;
}
int audioTrackIndex = AddTrackAudio(muxer, g_muxerParam.audioParams, fdStr->inAudioFd);
int videoTrackIndex = AddTrackVideo(muxer, g_muxerParam.videoParams, fdStr->inVideoFd);
int coverTrackIndex = AddTrackCover(muxer, g_muxerParam.coverParams, fdStr->inCoverFd);
if (OH_AVMuxer_Start(muxer) != AV_ERR_OK) {
printf("start muxer failed!\n");
return -1;
}
if (coverTrackIndex >= 0) {
WriteTrackCover(muxer, coverTrackIndex, fdStr->inCoverFd);
}
if (g_muxerParam.runMode == NORMAL) {
printf("== write audio video sample in same thread\n");
if (audioTrackIndex >= 0 && videoTrackIndex >= 0) {
WriteTrackSample(muxer, audioTrackIndex, videoTrackIndex, fdStr);
} else if (audioTrackIndex >= 0) {
WriteSingleTrackSample(muxer, audioTrackIndex, fdStr->inAudioFd);
} else if (videoTrackIndex >= 0) {
WriteSingleTrackSample(muxer, videoTrackIndex, fdStr->inVideoFd);
}
} else if (g_muxerParam.runMode == THREAD) {
printf("== write audio video sample in different thread\n");
pthread_t auThread;
pthread_t viThread;
struct WriteTrackSampleParam audioThParam = {muxer, audioTrackIndex, fdStr->inAudioFd};
struct WriteTrackSampleParam videoThparam = {muxer, videoTrackIndex, fdStr->inVideoFd};
pthread_create(&auThread, NULL, ThreadWriteTrackSample, &audioThParam);
pthread_create(&viThread, NULL, ThreadWriteTrackSample, &videoThparam);
pthread_join(viThread, NULL);
pthread_join(auThread, NULL);
}
if (OH_AVMuxer_Stop(muxer) != AV_ERR_OK) {
printf("stop muxer failed!\n");
return -1;
}
printf("native avmuxer finish! fd:out:%d, audio:%d, video:%d, cover:%d\n",
fdStr->outputFd, fdStr->inAudioFd, fdStr->inVideoFd, fdStr->inCoverFd);
return 0;
}
void CloseAllFd(FdListStr *fdStr)
{
printf("close fd : [");
int fdTotalCount = sizeof(*fdStr) /sizeof(fdStr->start[0]);
for (int i = 0; i < fdTotalCount; i++) {
printf("%d, ", fdStr->start[i]);
if (fdStr->start[i] > 0) {
close(fdStr->start[i]);
fdStr->start[i] = -1;
}
}
printf("\b\b]\n");
}
int RunNativeMuxer(const char *out)
{
FdListStr fdStr;
int fdTotalCount = sizeof(fdStr) /sizeof(fdStr.start[0]);
printf("fd list total size is %d\n", fdTotalCount);
for (int i = 0; i < fdTotalCount; i++) {
fdStr.start[i] = -1;
}
if (OpenAllInputFile(&fdStr) < 0) {
CloseAllFd(&fdStr);
return -1;
}
char outFileName[100] = {0};
snprintf(outFileName, sizeof(outFileName), "%s_%s_%s_%s_%s.%s",
out, g_muxerParam.runModeType, g_muxerParam.audioType, g_muxerParam.videoType,
g_muxerParam.coverType, g_muxerParam.outputFormatType);
fdStr.outputFd = open(outFileName, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
if (fdStr.outputFd < 0) {
printf("open file failed! filePath is: %s %d\n", outFileName, fdStr.outputFd);
CloseAllFd(&fdStr);
return -1;
}
printf("open file %s success, -fd:%d, -flags %x\n", outFileName, fdStr.outputFd, fcntl(fdStr.outputFd, F_GETFL, 0));
OH_AVMuxer *muxer = OH_AVMuxer_Create(fdStr.outputFd, g_muxerParam.outputFormat);
DoRunMuxer(&fdStr, muxer);
if (muxer != NULL) {
OH_AVMuxer_Destroy(muxer);
muxer = NULL;
}
CloseAllFd(&fdStr);
return 0;
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

89
test/unittest/BUILD.gn Normal file
View File

@ -0,0 +1,89 @@
# 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.
import("//build/test.gni")
import("//foundation/multimedia/av_codec/config.gni")
AV_CODE_ROOT_DIR = "//foundation/multimedia/av_codec"
module_output_path = "av_codec"
av_codec_unittest_include_dirs = [
"$AV_CODE_ROOT_DIR/interfaces/inner_api/native",
"$AV_CODE_ROOT_DIR/interfaces/interfaces/inner_api/native",
]
av_codec_unittest_cflags = [
"-std=c++17",
"-fno-rtti",
"-fno-exceptions",
"-Wall",
"-fno-common",
"-fstack-protector-strong",
"-Wshadow",
"-FPIC",
"-FS",
"-O2",
"-D_FORTIFY_SOURCE=2",
"-fvisibility=hidden",
"-Wformat=2",
"-Wdate-time",
"-Werror",
"-Wextra",
"-Wimplicit-fallthrough",
"-Wsign-compare",
"-Wunused-parameter",
]
##################################################################################################################
ohos_unittest("av_muxer_unit_test") {
module_out_path = module_output_path
include_dirs = av_codec_unittest_include_dirs
include_dirs += [
"./",
]
cflags = av_codec_unittest_cflags
if (multimedia_av_codec_support_muxer) {
sources = [
"./avmuxer_test/avmuxer_unittest.cpp",
]
}
external_deps = [
"multimedia_av_codec:av_codec_client",
]
resource_config_file = "$AV_CODE_ROOT_DIR/test/unittest/ohos_test.xml"
}
##################################################################################################################
ohos_unittest("format_unit_test") {
module_out_path = module_output_path
include_dirs = av_codec_unittest_include_dirs
include_dirs += [
"./",
]
cflags = av_codec_unittest_cflags
if (multimedia_av_codec_support_muxer) {
sources = [
"./format_unit_test.cpp",
]
}
public_deps = [
"$AV_CODE_ROOT_DIR/services/utils:av_codec_format",
]
resource_config_file = "$AV_CODE_ROOT_DIR/test/unittest/ohos_test.xml"
}

View File

@ -0,0 +1,257 @@
#include <gtest/gtest.h>
#include <iostream>
#include <fstream>
#include <string>
#include <fcntl.h>
#include "avmuxer.h"
#include "avcodec_info.h"
using namespace testing::ext;
using namespace OHOS::Media;
static const std::string TEST_FILE_PATH = "./";
class AvmuxerUnitTest : public testing::Test {
public:
// SetUpTestCase: Called before all test cases
static void SetUpTestCase(void);
// TearDownTestCase: Called after all test case
static void TearDownTestCase(void);
// SetUp: Called before each test cases
void SetUp(void);
// TearDown: Called after each test cases
void TearDown(void);
protected:
int32_t fd_ {-1};
std::shared_ptr<std::ifstream> avDataFile_ {nullptr};
std::shared_ptr<AVMuxer> avmuxer_ {nullptr};
uint8_t buffer_[3] = {'a', 'a', 'a'};
};
void AvmuxerUnitTest::SetUpTestCase() {}
void AvmuxerUnitTest::TearDownTestCase() {}
void AvmuxerUnitTest::SetUp()
{
avDataFile_ = std::make_shared<std::ifstream>();
avDataFile_->open("avDataMpegMpeg4.bin", std::ios::in | std::ios::binary);
if (avDataFile_ == nullptr) {
std::cout<<"open avDataMpegMpeg4.bin failed!"<<std::endl;
}
}
void AvmuxerUnitTest::TearDown()
{
if (avDataFile_ != nullptr) {
avDataFile_->close();
avDataFile_ = nullptr;
}
if (fd_ >= 0) {
close(fd_);
fd_ = -1;
}
}
/**
* @tc.name: Muxer_AddTrack_001
* @tc.desc: Muxer AddTrack add audio track
* @tc.type: FUNC
*/
HWTEST_F(AvmuxerUnitTest, Muxer_Create_001, TestSize.Level0)
{
std::string outputFile = TEST_FILE_PATH + std::string("Muxer_AddTrack_001.mp4");
fd_ = open(outputFile.c_str(), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4;
std::shared_ptr<AVMuxer> avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat);
ASSERT_EQ(avmuxer, nullptr);
close(fd_);
fd_ = open(outputFile.c_str(), O_CREAT | O_RDONLY, S_IRUSR | S_IWUSR);
outputFormat = OUTPUT_FORMAT_MPEG_4;
avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat);
ASSERT_EQ(avmuxer, nullptr);
close(fd_);
fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
outputFormat = OUTPUT_FORMAT_MPEG_4;
avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat);
ASSERT_NE(avmuxer, nullptr);
}
/**
* @tc.name: Muxer_AddTrack_001
* @tc.desc: Muxer AddTrack add audio track
* @tc.type: FUNC
*/
HWTEST_F(AvmuxerUnitTest, Muxer_AddTrack_001, TestSize.Level0)
{
int audioTrackId = -1;
int ret = 0;
std::string outputFile = TEST_FILE_PATH + std::string("Muxer_AddTrack_001.mp4");
fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4;
std::shared_ptr<AVMuxer> avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat);
ASSERT_NE(avmuxer, nullptr);
std::shared_ptr<MediaDescription> audioParams = std::make_shared<MediaDescription>();
audioParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::AUDIO_MPEG);
audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, 44100);
audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, 2);
ret = avmuxer->AddTrack(audioTrackId, *audioParams);
EXPECT_EQ(ret, 0);
EXPECT_GE(audioTrackId, 0);
audioParams = std::make_shared<MediaDescription>();
audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, 44100);
audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, 2);
ret = avmuxer->AddTrack(audioTrackId, *audioParams);
EXPECT_NE(ret, 0);
audioParams = std::make_shared<MediaDescription>();
audioParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::AUDIO_MPEG);
audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, 2);
ret = avmuxer->AddTrack(audioTrackId, *audioParams);
EXPECT_NE(ret, 0);
audioParams = std::make_shared<MediaDescription>();
audioParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::AUDIO_MPEG);
audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, 44100);
ret = avmuxer->AddTrack(audioTrackId, *audioParams);
EXPECT_NE(ret, 0);
}
/**
* @tc.name: Muxer_AddTrack_002
* @tc.desc: Muxer AddTrack add video track
* @tc.type: FUNC
*/
HWTEST_F(AvmuxerUnitTest, Muxer_AddTrack_002, TestSize.Level0)
{
int videoTrackId = -1;
int ret = 0;
std::string outputFile = TEST_FILE_PATH + std::string("Muxer_AddTrack_002.mp4");
fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4;
std::shared_ptr<AVMuxer> avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat);
ASSERT_NE(avmuxer, nullptr);
std::shared_ptr<MediaDescription> videoParams = std::make_shared<MediaDescription>();
videoParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_MPEG4);
videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352);
videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288);
ret = avmuxer->AddTrack(videoTrackId, *videoParams);
EXPECT_EQ(ret, 0);
EXPECT_GE(videoTrackId, 0);
videoParams = std::make_shared<MediaDescription>();
videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352);
videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288);
ret = avmuxer->AddTrack(videoTrackId, *videoParams);
EXPECT_NE(ret, 0);
videoParams = std::make_shared<MediaDescription>();
videoParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_MPEG4);
videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288);
ret = avmuxer->AddTrack(videoTrackId, *videoParams);
EXPECT_NE(ret, 0);
videoParams = std::make_shared<MediaDescription>();
videoParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_MPEG4);
videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352);
ret = avmuxer->AddTrack(videoTrackId, *videoParams);
EXPECT_NE(ret, 0);
}
/**
* @tc.name: Muxer_AddTrack_003
* @tc.desc: Muxer AddTrack after Start()
* @tc.type: FUNC
*/
HWTEST_F(AvmuxerUnitTest, Muxer_AddTrack_003, TestSize.Level0)
{
int audioTrackId = -1;
int videoTrackId = -1;
int ret = 0;
std::string outputFile = TEST_FILE_PATH + std::string("Muxer_AddTrack_003.mp4");
fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4;
std::shared_ptr<AVMuxer> avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat);
ASSERT_NE(avmuxer, nullptr);
std::shared_ptr<MediaDescription> videoParams = std::make_shared<MediaDescription>();
videoParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_MPEG4);
videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352);
videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288);
videoParams->PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, buffer_, 3);
ret = avmuxer->AddTrack(videoTrackId, *videoParams);
EXPECT_EQ(ret, 0);
EXPECT_GE(videoTrackId, 0);
avmuxer->Start();
std::shared_ptr<MediaDescription> audioParams = std::make_shared<MediaDescription>();
audioParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::AUDIO_MPEG);
audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, 44100);
audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, 2);
ret = avmuxer->AddTrack(audioTrackId, *audioParams);
EXPECT_NE(ret, 0);
}
/**
* @tc.name: Muxer_Start_001
* @tc.desc: Muxer Start after Stop()
* @tc.type: FUNC
*/
HWTEST_F(AvmuxerUnitTest, Muxer_Start_001, TestSize.Level0)
{
std::string outputFile = TEST_FILE_PATH + std::string("Muxer_AddTrack_003.mp4");
fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4;
std::shared_ptr<AVMuxer> avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat);
ASSERT_NE(avmuxer, nullptr);
std::shared_ptr<MediaDescription> videoParams = std::make_shared<MediaDescription>();
videoParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_MPEG4);
videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352);
videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288);
videoParams->PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, buffer_, 3);
EXPECT_NE(avmuxer->Start(), 0);
int32_t videoTrackId = -1;
int ret = avmuxer->AddTrack(videoTrackId, *videoParams);
ASSERT_EQ(ret, 0);
EXPECT_GE(videoTrackId, 0);
EXPECT_EQ(avmuxer->Start(), 0);
EXPECT_NE(avmuxer->Start(), 0);
EXPECT_EQ(avmuxer->Stop(), 0);
EXPECT_NE(avmuxer->Start(), 0);
}
/**
* @tc.name: Muxer_Stop_001
* @tc.desc: Muxer Stop() before Start
* @tc.type: FUNC
*/
HWTEST_F(AvmuxerUnitTest, Muxer_Stop_001, TestSize.Level0)
{
std::string outputFile = TEST_FILE_PATH + std::string("Muxer_AddTrack_003.mp4");
fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4;
std::shared_ptr<AVMuxer> avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat);
ASSERT_NE(avmuxer, nullptr);
std::shared_ptr<MediaDescription> videoParams = std::make_shared<MediaDescription>();
videoParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_MPEG4);
videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352);
videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288);
videoParams->PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, buffer_, 3);
int32_t videoTrackId = -1;
int ret = avmuxer->AddTrack(videoTrackId, *videoParams);
ASSERT_EQ(ret, 0);
EXPECT_GE(videoTrackId, 0);
EXPECT_NE(avmuxer->Stop(), 0);
EXPECT_EQ(avmuxer->Start(), 0);
EXPECT_EQ(avmuxer->Stop(), 0);
EXPECT_NE(avmuxer->Stop(), 0);
}

View File

@ -0,0 +1,117 @@
#include <string>
#include <cmath>
#include <gtest/gtest.h>
#include "format.h"
using namespace testing::ext;
using namespace OHOS::Media;
namespace {
constexpr float EPSINON_FLOAT = 0.0001;
constexpr double EPSINON_DOUBLE = 0.0001;
} // namespace FormatTestParam
class FormatUnitTest : public testing::Test {
public:
// SetUpTestCase: Called before all test cases
static void SetUpTestCase(void);
// TearDownTestCase: Called after all test case
static void TearDownTestCase(void);
// SetUp: Called before each test cases
void SetUp(void);
// TearDown: Called after each test cases
void TearDown(void);
std::unique_ptr<Format> format_ {nullptr};
};
void FormatUnitTest::SetUpTestCase() {}
void FormatUnitTest::TearDownTestCase() {}
void FormatUnitTest::SetUp()
{
format_ = std::make_unique<Format>();
}
void FormatUnitTest::TearDown()
{
format_ = nullptr;
}
/**
* @tc.name: Format_Value_0100
* @tc.desc: format put and get value
* @tc.type: FUNC
* @tc.require: issueI5OX06 issueI5P8N0
*/
HWTEST_F(FormatUnitTest, Format_Value_0100, TestSize.Level0)
{
const std::string_view intKey = "IntKey";
const std::string_view longKey = "LongKey";
const std::string_view floatKey = "FloatKey";
const std::string_view doubleKey = "DoubleKey";
const std::string_view stringKey = "StringKey";
int32_t intValue = 1;
int64_t longValue = 1;
float floatValue = 1.0;
double doubleValue = 1.0;
const std::string stringValue = "StringValue";
int32_t getIntValue = 0;
int64_t getLongValue = 0;
float getFloatValue = 0.0;
double getDoubleValue = 0.0;
std::string getStringValue = "";
ASSERT_TRUE(format_ != nullptr);
ASSERT_TRUE(format_->PutIntValue(intKey, intValue));
ASSERT_TRUE(format_->GetIntValue(intKey, getIntValue));
ASSERT_TRUE(intValue == getIntValue);
ASSERT_FALSE(format_->GetLongValue(intKey, getLongValue));
ASSERT_TRUE(format_->PutLongValue(longKey, intValue));
ASSERT_TRUE(format_->GetLongValue(longKey, getLongValue));
ASSERT_TRUE(longValue == getLongValue);
ASSERT_FALSE(format_->GetIntValue(longKey, getIntValue));
ASSERT_TRUE(format_->PutFloatValue(floatKey, floatValue));
ASSERT_TRUE(format_->GetFloatValue(floatKey, getFloatValue));
ASSERT_TRUE(fabs(floatValue - getFloatValue) < EPSINON_FLOAT);
ASSERT_FALSE(format_->GetDoubleValue(floatKey, getDoubleValue));
ASSERT_TRUE(format_->PutDoubleValue(doubleKey, doubleValue));
ASSERT_TRUE(format_->GetDoubleValue(doubleKey, getDoubleValue));
ASSERT_TRUE(fabs(doubleValue - getDoubleValue) < EPSINON_DOUBLE);
ASSERT_FALSE(format_->GetFloatValue(doubleKey, getFloatValue));
ASSERT_TRUE(format_->PutStringValue(stringKey, stringValue.c_str()));
ASSERT_TRUE(format_->GetStringValue(stringKey, getStringValue));
ASSERT_TRUE(stringValue == getStringValue);
}
/**
* @tc.name: Format_Buffer_0100
* @tc.desc: format put and get buffer
* @tc.type: FUNC
* @tc.require: issueI5OWXY issueI5OXCD
*/
HWTEST_F(FormatUnitTest, Format_Buffer_0100, TestSize.Level0)
{
constexpr size_t size = 3;
const std::string_view key = "BufferKey";
uint8_t buffer[size] = {'a', 'b', 'b'};
ASSERT_TRUE(format_->PutBuffer(key, buffer, size));
uint8_t *getBuffer;
size_t getSize;
ASSERT_TRUE(format_->GetBuffer(key, &getBuffer, getSize));
ASSERT_TRUE(size == getSize);
for (int32_t i = 0; i < size; i++) {
ASSERT_TRUE(buffer[i] == getBuffer[i]);
}
std::string getString;
ASSERT_FALSE(format_->GetStringValue(key, getString));
}

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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.
-->
<configuration ver="2.0">
<target name="av_muxer_unit_test">
</target>
</configuration>