# 媒体子系统
- [简介](#section38510214395)
- [目录结构](#section1937963913399)
- [约束](#section722512541395)
- [安装](#section11914418405)
- [使用](#section1467220266400)
- [涉及仓](#section7666411192217)
## 简介
该仓主要用于存放媒体子系统的源码信息,旨在为多媒体应用开发者开发者提供统一的开发接口,使得开发者可以专注于应用业务的开发,轻松使用多媒体的资源。下图分别展现媒体子系统的框架及业务流程。
**图 1** 媒体子系统框架图
![](figures/媒体子系统框架图.png "媒体子系统框架图")
媒体子系统框架支持相机、录像和播放业务功能,这些功能支持JS应用开发及各种使用媒体能力的KIT模块开发,媒体子系统框架包括框架层,框架层对外提供应用调用的native接口及其对应的业务实现,针对相机、录像及播放业务,框架层实现了音视频输入输出,音视频编解码,视频文件的打包及解复用等功能。系统服务层,系统服务层利用平台提供的能力去实现对底层硬件及相关驱动使用。
**图 2** 媒体子系统业务流程图
![](figures/媒体子系统业务流程图.png "媒体子系统业务流程图")
多媒体包括camera,recorder和player,camera提供YUV、RGB、JPEG以及H264,H265数据到共享内存surface中,recorder模块将surface中h264/h265数据和音频aac数据打包成mp4文件,player模块把mp4文件解复用成音频和视频数据,分别送入对应编码器解码,然后进行播放。
## 目录结构
其中媒体子系统框架的源代码目录结构如下(只列举了主要部分):
```
foundation/multimedia # 媒体子系统主目录
├── audio_lite
│ ├── frameworks # 音频框架模块实现
│ └── interfaces # 音频框架模块接口定义
├── camera_lite
│ ├── frameworks # 相机框架模块实现
│ └── interfaces # 相机框架模块接口定义
├── media_lite
│ ├── frameworks
│ │ ├── player_lite # 播放框架模块实现
│ │ └── recorder_lite # 录制框架模块实现
│ └── interfaces
│ │ └── kits
│ │ ├── player_lite # 播放框架模块接口实现
│ │ └── recorder_lite # 录制框架模块接口实现
│ ├── services # 服务启动代码
│ └── test # 测试代码
└── utils
└── lite # 应用接口通用模块实现
└── hals # 定义媒体适配的接口头文件
```
## 约束
- C++11版本或以上
## 安装
- 请提前加载内核及相关驱动,参考内核及驱动子系统readme。
- 配置合适的配置文件,可以参考applications/sample/camera/media下配置文件,如果适配其他sensor可在开源社区中求助。用户使用时将配置文件放入到开发板/storage/data目录,开发者通过该配置文件可以去适配sensor及分辨率、帧率等能力。
## 使用
Native应用接口调用可以参考applications/sample/camera/media下demo实现
应用开发者使用多媒体接口实现录像、预览和播放音视频,使用可以参考《多媒体开发指南》。
开发者先创建camerakit组件对象,注册各种事件回调,这些事件回调是用来响应多媒体模块中事件响应的,之后调用创建camera就可以创建一个操作camera资源的对象,使用这个对象可以启动预览、录像或抓拍取流,及设置取流的相关参数。
重写事件类的代码实例如下:
```
#include "camera_kit.h"
#include "recorder.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace OHOS;
using namespace OHOS::Media;
static int32_t SampleGetRecordFd()
{
struct timeval tv = {};
gettimeofday(&tv, nullptr);
struct tm *ltm = localtime(&tv.tv_sec);
int32_t fd = -1;
if (ltm != nullptr) {
ostringstream ss("Capture_");
ss << "Record" << ltm->tm_hour << "-" << ltm->tm_min << "-" << ltm->tm_sec << ".mp4";
fd = open(("/sdcard/" + ss.str()).c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
cout << "Open "
<< "/sdcard/" << ss.str() << endl;
if (fd == -1) {
cout << "Open recorder file failed. strerr=" << strerror(errno) << endl;
}
}
return fd;
}
static void SampleSaveCapture(const char *p, uint32_t size)
{
cout << "Start saving picture" << endl;
struct timeval tv = {};
gettimeofday(&tv, nullptr);
struct tm *ltm = localtime(&tv.tv_sec);
if (ltm != nullptr) {
ostringstream ss("Capture_");
ss << "Capture" << ltm->tm_hour << "-" << ltm->tm_min << "-" << ltm->tm_sec << ".jpg";
ofstream pic("/sdcard/" + ss.str(), ofstream::out | ofstream::trunc);
cout << "write " << size << " bytes" << endl;
pic.write(p, size);
pic.close();
cout << "Saving picture end" << endl;
}
}
Recorder *SampleCreateRecorder()
{
int ret = 0;
int32_t sampleRate = 48000;
int32_t channelCount = 1;
AudioCodecFormat audioFormat = AAC_LC;
AudioSourceType inputSource = AUDIO_MIC;
int32_t audioEncodingBitRate = sampleRate;
VideoSourceType source = VIDEO_SOURCE_SURFACE_ES;
int32_t frameRate = 30;
double fps = 30;
int32_t rate = 4096;
int32_t sourceId = 0;
int32_t audioSourceId = 0;
int32_t width = 1920;
int32_t height = 1080;
VideoCodecFormat encoder;
encoder = HEVC;
width = 1920;
height = 1080;
Recorder *recorder = new Recorder();
if ((ret = recorder->SetVideoSource(source, sourceId)) != SUCCESS) {
cout << "SetVideoSource failed." << ret << endl;
goto ERROR;
}
if ((ret = recorder->SetVideoEncoder(sourceId, encoder)) != SUCCESS) {
cout << "SetVideoEncoder failed." << ret << endl;
goto ERROR;
}
if ((ret = recorder->SetVideoSize(sourceId, width, height)) != SUCCESS) {
cout << "SetVideoSize failed." << ret << endl;
goto ERROR;
}
if ((ret = recorder->SetVideoFrameRate(sourceId, frameRate)) != SUCCESS) {
cout << "SetVideoFrameRate failed." << ret << endl;
goto ERROR;
}
if ((ret = recorder->SetVideoEncodingBitRate(sourceId, rate)) != SUCCESS) {
cout << "SetVideoEncodingBitRate failed." << ret << endl;
goto ERROR;
}
if ((ret = recorder->SetCaptureRate(sourceId, fps)) != SUCCESS) {
cout << "SetCaptureRate failed." << ret << endl;
goto ERROR;
}
if ((ret = recorder->SetAudioSource(inputSource, audioSourceId)) != SUCCESS) {
cout << "SetAudioSource failed." << ret << endl;
goto ERROR;
}
if ((ret = recorder->SetAudioEncoder(audioSourceId, audioFormat)) != SUCCESS) {
cout << "SetAudioEncoder failed." << ret << endl;
goto ERROR;
}
if ((ret = recorder->SetAudioSampleRate(audioSourceId, sampleRate)) != SUCCESS) {
cout << "SetAudioSampleRate failed." << ret << endl;
goto ERROR;
}
if ((ret = recorder->SetAudioChannels(audioSourceId, channelCount)) != SUCCESS) {
cout << "SetAudioChannels failed." << ret << endl;
goto ERROR;
}
if ((ret = recorder->SetAudioEncodingBitRate(audioSourceId, audioEncodingBitRate)) != SUCCESS) {
cout << "SetAudioEncodingBitRate failed." << ret << endl;
goto ERROR;
}
if ((ret = recorder->SetMaxDuration(36000)) != SUCCESS) { // 36000s=10h
cout << "SetAudioEncodingBitRate failed." << ret << endl;
goto ERROR;
}
return recorder;
ERROR:
delete recorder;
return nullptr;
}
class SampleFrameStateCallback : public FrameStateCallback {
void OnFrameFinished(Camera &camera, FrameConfig &fc, FrameResult &result) override
{
cout << "Receive frame complete inform." << endl;
if (fc.GetFrameConfigType() == FRAME_CONFIG_CAPTURE) {
cout << "Capture frame received." << endl;
list surfaceList = fc.GetSurfaces();
for (Surface *surface : surfaceList) {
SurfaceBuffer *buffer = surface->AcquireBuffer();
if (buffer != nullptr) {
char *virtAddr = static_cast(buffer->GetVirAddr());
if (virtAddr != nullptr) {
SampleSaveCapture(virtAddr, buffer->GetSize());
}
surface->ReleaseBuffer(buffer);
}
delete surface;
}
}
delete &fc;
}
};
class SampleCameraStateMng : public CameraStateCallback {
public:
SampleCameraStateMng() = delete;
SampleCameraStateMng(EventHandler &eventHdlr) : eventHdlr_(eventHdlr) {}
~SampleCameraStateMng()
{
CloseRecorder();
}
void OnCreated(Camera &c) override
{
cout << "Sample recv OnCreate camera." << endl;
auto config = CameraConfig::CreateCameraConfig();
config->SetFrameStateCallback(&fsCb_, &eventHdlr_);
c.Configure(*config);
cam_ = &c;
}
void OnCreateFailed(const std::string cameraId, int32_t errorCode) override {}
void OnReleased(Camera &c) override {}
void CloseRecorder()
{
if (recorder_ != nullptr) {
recorder_->Stop(true);
recorder_->Release();
delete recorder_;
recorder_ = nullptr;
}
if (recordFd_ != -1) {
close(recordFd_);
recordFd_ = -1;
}
}
int PrepareRecorder()
{
if (cam_ == nullptr) {
cout << "Camera is not ready." << endl;
return -1;
}
if (recorder_ == nullptr) {
recorder_ = SampleCreateRecorder();
}
if (recorder_ == nullptr) {
cout << "Recorder not available." << endl;
return -1;
}
if (recordFd_ == -1) {
recordFd_ = SampleGetRecordFd();
}
if (recordFd_ == -1) {
cout << "Create fd failed." << endl;
return -1;
}
return SUCCESS;
}
void StartRecord()
{
if (recordState_ == STATE_RUNNING) {
cout << "Camera is already recording." << endl;
return;
}
int ret = PrepareRecorder();
if (ret != SUCCESS) {
cout << "PrepareRecorder failed." << endl;
CloseRecorder();
return;
}
ret = recorder_->SetOutputFile(recordFd_);
if (ret != SUCCESS) {
cout << "SetOutputPath failed. ret=" << ret << endl;
CloseRecorder();
return;
}
ret = recorder_->Prepare();
if (ret != SUCCESS) {
cout << "Prepare failed. ret=" << ret << endl;
CloseRecorder();
return;
}
ret = recorder_->Start();
if (ret != SUCCESS) {
cout << "recorder start failed. ret=" << ret << endl;
CloseRecorder();
return;
}
FrameConfig *fc = new FrameConfig(FRAME_CONFIG_RECORD);
Surface *surface = (recorder_->GetSurface(0)).get();
surface->SetWidthAndHeight(1920, 1080);
surface->SetQueueSize(3);
surface->SetSize(1024 * 1024);
fc->AddSurface(*surface);
ret = cam_->TriggerLoopingCapture(*fc);
if (ret != 0) {
delete fc;
CloseRecorder();
cout << "camera start recording failed. ret=" << ret << endl;
return;
}
recordState_ = STATE_RUNNING;
cout << "camera start recording succeed." << endl;
}
void StartPreview()
{
if (cam_ == nullptr) {
cout << "Camera is not ready." << endl;
return;
}
if (previewState_ == STATE_RUNNING) {
cout << "Camera is already previewing." << endl;
return;
}
FrameConfig *fc = new FrameConfig(FRAME_CONFIG_PREVIEW);
Surface *surface = Surface::CreateSurface();
if (surface == nullptr) {
delete fc;
cout << "CreateSurface failed" << endl;
return;
}
surface->SetWidthAndHeight(1920, 1080); /* 1920:width,1080:height */
surface->SetUserData("region_position_x", "0");
surface->SetUserData("region_position_y", "0");
surface->SetUserData("region_width", "480");
surface->SetUserData("region_height", "480");
fc->AddSurface(*surface);
int32_t ret = cam_->TriggerLoopingCapture(*fc);
if (ret != 0) {
delete fc;
cout << "camera start preview failed. ret=" << ret << endl;
return;
}
delete surface;
previewState_ = STATE_RUNNING;
cout << "camera start preview succeed." << endl;
}
void Capture()
{
if (cam_ == nullptr) {
cout << "Camera is not ready." << endl;
return;
}
FrameConfig *fc = new FrameConfig(FRAME_CONFIG_CAPTURE);
Surface *surface = Surface::CreateSurface();
if (surface == nullptr) {
delete fc;
cout << "CreateSurface failed" << endl;
return;
}
surface->SetWidthAndHeight(1920, 1080); /* 1920:width,1080:height */
fc->AddSurface(*surface);
cam_->TriggerSingleCapture(*fc);
}
void Stop()
{
if (cam_ == nullptr) {
cout << "Camera is not ready." << endl;
return;
}
cam_->StopLoopingCapture();
if (recordState_ == STATE_RUNNING) {
CloseRecorder();
}
recordState_ = STATE_IDLE;
previewState_ = STATE_IDLE;
}
private:
enum State : int32_t { STATE_IDLE, STATE_RUNNING, STATE_BUTT };
State previewState_ = STATE_IDLE;
State recordState_ = STATE_IDLE;
EventHandler &eventHdlr_;
Camera *cam_ = nullptr;
int32_t recordFd_ = -1;
Recorder *recorder_ = nullptr;
SampleFrameStateCallback fsCb_;
};
class SampleCameraDeviceCallback : public CameraDeviceCallback {
};
void SampleHelp()
{
cout << "*******************************************" << endl;
cout << "Select the behavior of avrecorder." << endl;
cout << "1: Capture" << endl;
cout << "2: Record(Press s to stop)" << endl;
cout << "3: Preview(Press s to stop)" << endl;
cout << "q: quit the sample." << endl;
cout << "*******************************************" << endl;
}
int main()
{
cout << "Camera sample begin." << endl;
SampleHelp();
CameraKit *camKit = CameraKit::GetInstance();
if (camKit == nullptr) {
cout << "Can not get CameraKit instance" << endl;
return 0;
}
list camList = camKit->GetCameraIds();
string camId;
for (auto &cam : camList) {
cout << "camera name:" << cam << endl;
const CameraAbility *ability = camKit->GetCameraAbility(cam);
/* find camera which fits user's ability */
list sizeList = ability->GetSupportedSizes(0);
for (auto &pic : sizeList) {
if (pic.width == 1920 && pic.height == 1080) {
camId = cam;
break;
}
}
}
if (camId.empty()) {
cout << "No available camera.(1080p wanted)" << endl;
return 0;
}
EventHandler eventHdlr; // Create a thread to handle callback events
SampleCameraStateMng CamStateMng(eventHdlr);
camKit->CreateCamera(camId, CamStateMng, eventHdlr);
char input;
while (cin >> input) {
switch (input) {
case '1':
CamStateMng.Capture();
break;
case '2':
CamStateMng.StartRecord();
break;
case '3':
CamStateMng.StartPreview();
break;
case 's':
CamStateMng.Stop();
break;
case 'q':
CamStateMng.Stop();
goto EXIT;
default:
SampleHelp();
break;
}
}
EXIT:
cout << "Camera sample end." << endl;
return 0;
}
```
## 涉及仓
/hmf/multimedia/camera\_lite
/hmf/multimedia/audio\_lite
/hmf/multimedia/media\_lite
/hmf/multimedia/utils\_lite