Pipe API¶
Oasis Pipe는 프로세스간 통신(IPC)를 지원합니다.
oasis 네임스페이스를 사용합니다.
영상이나 오디오 데이터 전송에 특화되어 있습니다. 영상 데이터를 v4l2loopback 장치에 쓸 때 유용합니다.
Oasis Pipe는 다른 Oasis 컴포넌트에 의존적이지 않고, oasis::initialize 없이도 사용가능하므로 Oasis를 사용하지 않는 응용프로그램에서도 liboasis_pipe.so 라이브러리를 링크하며 사용할 수 있습니다.
헤더 파일¶
OasisPipe.h
형정의¶
Oasis Pipe가 지원하는 데이터 포맷은 아래와 같습니다. 영상의 경우, V4L2 포맷과 호환됩니다.
enum {
kOasisPipeDataTypeUserData = 0,
kOasisPipeDataTypeVideoBGRA,
kOasisPipeDataTypeVideoARGB,
kOasisPipeDataTypeVideoYUYV,
kOasisPipeDataTypeVideoYVYU,
kOasisPipeDataTypeVideoYUV420,
kOasisPipeDataTypeVideoYVU420,
kOasisPipeDataTypeVideoNV12,
kOasisPipeDataTypeVideoNV21,
kOasisPipeDataTypeAudioPCM16LE,
kOasisPipeDataTypeAudioPCM16BE,
//in case of the following types, width_or_sampling_rate, height_or_channels, stride_or_bits_per_sample are ignored.
kOasisPipeDataTypeVideoH264,
kOasisPipeDataTypeVideoH265,
kOasisPipeDataTypeVideoVP8,
kOasisPipeDataTypeVideoVP9,
kOasisPipeDataTypeVideoMJPEG,
};
int32_t
pipeDataTypeToV4l2Format
(
int32_t
data_type
)
OasisPipe.h
Oasis 파이프 데이터 타입을 V4L2 포맷 타입으로 변환합니다.
매개변수
data_type
Oasis 파이프 데이터 타입니다.
리턴값
V4L2 포맷 타입니다. 지원하지 않을 경우, -1을 리턴합니다.
아래와 같이 변환됩니다.
| From | To |
|---|---|
| kOasisPipeDataTypeVideoBGRA | V4L2_PIX_FMT_ABGR32 |
| kOasisPipeDataTypeVideoARGB | V4L2_PIX_FMT_ARGB32 |
| kOasisPipeDataTypeVideoYUYV | V4L2_PIX_FMT_YUYV |
| kOasisPipeDataTypeVideoYVYU | V4L2_PIX_FMT_YYUV |
| kOasisPipeDataTypeVideoYUV420 | V4L2_PIX_FMT_YUV420 |
| kOasisPipeDataTypeVideoYVU420 | V4L2_PIX_FMT_YVU420 |
| kOasisPipeDataTypeVideoNV12 | V4L2_PIX_FMT_NV12 |
| kOasisPipeDataTypeVideoNV21 | V4L2_PIX_FMT_NV21 |
| kOasisPipeDataTypeVideoH264 | V4L2_PIX_FMT_H264 |
| kOasisPipeDataTypeVideoH265 | V4L2_PIX_FMT_H265 |
| kOasisPipeDataTypeVideoVP8 | V4L2_PIX_FMT_VP8 |
| kOasisPipeDataTypeVideoVP9 | V4L2_PIX_FMT_VP9 |
| kOasisPipeDataTypeVideoMJPEG | V4L2_PIX_FMT_MJPEG |
int32_t
v4l2FormatToPipeDataType
(
int32_t
format
)
OasisPipe.h
V4L2 포맷 타입을 Oasis 파이프 데이터 타입으로 변환합니다.
매개변수
format
V4L2 포맷 타입입니다.
리턴값
Oasis 파이프 데이터 타입을 리턴합니다. 지원하지 않을 경우, -1을 리턴합니다.
아래와 같이 변환됩니다.
| From | To |
|---|---|
| V4L2_PIX_FMT_BGR32 | kOasisPipeDataTypeVideoBGRA |
| V4L2_PIX_FMT_ABGR32 | kOasisPipeDataTypeVideoBGRA |
| V4L2_PIX_FMT_RGB32 | kOasisPipeDataTypeVideoARGB |
| V4L2_PIX_FMT_ARGB32 | kOasisPipeDataTypeVideoARGB |
| V4L2_PIX_FMT_YUYV | kOasisPipeDataTypeVideoYUYV |
| V4L2_PIX_FMT_YYUV | kOasisPipeDataTypeVideoYVYU |
| V4L2_PIX_FMT_YUV420 | kOasisPipeDataTypeVideoYUV420 |
| V4L2_PIX_FMT_YVU420 | kOasisPipeDataTypeVideoYVU420 |
| V4L2_PIX_FMT_NV12 | kOasisPipeDataTypeVideoNV12 |
| V4L2_PIX_FMT_NV21 | kOasisPipeDataTypeVideoNV21 |
| V4L2_PIX_FMT_H264 | kOasisPipeDataTypeVideoH264 |
| V4L2_PIX_FMT_H265 | kOasisPipeDataTypeVideoH265 |
| V4L2_PIX_FMT_VP8 | kOasisPipeDataTypeVideoVP8 |
| V4L2_PIX_FMT_VP9 | kOasisPipeDataTypeVideoVP9 |
| V4L2_PIX_FMT_MJPEG | kOasisPipeDataTypeVideoMJPEG |
Writer¶
OasisPipeWriterRef
pipeWriterOpen
(
const char *
pipe_path
)
OasisPipe.h
파이프 쓰기 객체를 생성합니다.
매개변수
pipe_path
파이프 경로입니다. 경로가 /dev/video 로 시작하면 v4l2loopback 장치로 간주하여 영상 데이터 쓰는 용도로 쓰기 객체를 생성합니다.
리턴값
성공하면 파이프 쓰기 객체를 리턴합니다. 실패하면 nullptr을 리턴합니다.
int32_t
pipeWriterClose
(
OasisPipeWriterRef &
pipe
)
OasisPipe.h
파이프 쓰기 객체를 해제합니다.
매개변수
pipe
파이프 쓰기 객체입니다.
리턴값
- 0: 성공
- -1: 실패
ssize_t
pipeWriterWrite
(
const OasisPipeWriterRef &
pipe
,
const void *
data
,
size_t
length
,
int32_t
width_or_sampling_rate
,
int32_t
height_or_channels
,
int32_t
stride_or_bits_per_sample
,
int32_t
data_type
,
uint32_t
flags
)
OasisPipe.h
파이프에 데이터를 전송합니다.
매개변수
pipe
파이프 쓰기 객체입니다.
data
데이터 포인터입니다.
length
데이터 길이입니다. 바이트 단위입니다.
width_or_sampling_rate
영상 데이터의 경우 너비 값을, 오디오 데이터의 경우 샘플링 레이트를 지정합니다. 사용자 데이터일 경우 임의로 정의하여 사용합니다.
height_or_channels
영상 데이터의 경우 높이 값을, 오디오 데이터의 경우 채널 개수를 지정합니다. 사용자 데이터일 경우 임의로 정의하여 사용합니다.
stride_or_bits_per_sample
영상 데이터의 경우 너비 스트라이드 값을, 오디오 데이터의 경우 샘플 크기를 지정합니다. 사용자 데이터일 경우 임의로 정의하여 사용합니다.
data_type
파이프 데이터 타입을 지정합니다.
flags
플래그 값을 지정합니다. 0값을 입력합니다.
리턴값
성공하면 데이터 길이를 리턴합니다. 실패하면 -1을 리턴하고, 에러 콜백 함수가 등록되었으면 상세 정보가 콜백 함수를 호출하여 전달됩니다.
void
pipeWriterSetErrorCallback
(
const OasisPipeWriterRef &
pipe
,
std::function<void(int32_t, const void *, size_t, void *)>
error_callback
,
void *
user
)
OasisPipe.h
쓰는 동안 에러 이벤트가 발생하였을 때 호출되는 콜백 함수를 등록합니다.
매개변수
pipe
파이프 쓰기 객체입니다.
error_callback
user
콜백 함수에 매개변수로 전달될 사용자 데이터입니다.
에러 이벤트 콜백 함수는 아래와 같습니다.
typedef
void
(*error_callback_)
(
int32_t
errno
, const void *
data
, size_t
length
, void *
user_data
)
OasisPipe.h
매개변수
errno
errno 값입니다.
data
쓰기 호출 때 전달된 데이터 포인터 입니다.
length
쓰기 호출 때 전달된 데이터 길이입니다.
user_data
콜백 등록 시 전달된 사용자 데이터입니다.
Reader¶
OasisPipeReaderRef
pipeReaderOpen
(
const char *
pipe_path
)
OasisPipe.h
파이프 읽기 객체를 생성합니다.
매개변수
pipe_path
파이프 경로입니다.
리턴값
성공하면 파이프 읽기 객체를 리턴합니다. 실패하면 nullptr을 리턴합니다.
void
pipeReaderSetCallback
(
const OasisPipeReaderRef &
pipe
,
std::function<void(const void *, size_t, int32_t, int32_t, int32_t, int32_t, uint32_t)>
callback
)
OasisPipe.h
파이프에서 완전한 데이터를 읽었을 때 호출되는 콜백 함수를 등록합니다.
매개변수
pipe
파이프 읽기 객체입니다.
callback
읽기 콜백 함수를 등록합니다.
읽기 콜백 함수 형정의는 아래와 같습니다.
typedef
void
(*callback)
(
const void *
data
, size_t
size
, int32_t
width_or_sampling_rate
, int32_t
height_or_channels
, int32_t
stride_or_bits_per_sample
, int32_t
data_type
, uint32_t
flags
)
OasisPipe.h
매개변수
data
데이터가 저장된 버퍼 포인터입니다.
size
데이터 길이입니다. 바이트 단위입니다.
width_or_sampling_rate
영상 데이터의 경우 너비 값을, 오디오 데이터의 경우 샘플링 레이트를 의미합니다. 사용자 데이터일 경우 임의로 정의하여 사용합니다.
height_or_channels
영상 데이터의 경우 높이 값을, 오디오 데이터의 경우 채널 개수를 의미합니다. 사용자 데이터일 경우 임의로 정의하여 사용합니다.
stride_or_bits_per_sample
영상 데이터의 경우 너비 스트라이드 값을, 오디오 데이터의 경우 샘플 크기를 의미합니다. 사용자 데이터일 경우 임의로 정의하여 사용합니다.
data_type
데이터 타입입니다.
flags
플래그 값입니다.
int32_t
pipeReaderClose
(
OasisPipeReaderRef &
pipe
)
OasisPipe.h
파이프 읽기 객체를 해제합니다.
매개변수
pipe
파이프 읽기 객체입니다.
리턴값
- 0: 성공
- -1: 실패
예제¶
아래는 한 프로세스에서 다른 프로세스에 OFFS 포맷을 파이프로 요청하고 그 응답을 파이프로 받는 예입니다.
JSON 처리를 위해 JsonCpp 라이브러리를 사용합니다.
명령 요청 프로세스¶
읽기 쓰기 파이프를 생성하고 각각 콜백을 등록합니다.
OasisPipeReaderRef pipe_reader_ = pipeReaderOpen("/tmp/oasis-mon-res");
pipeReaderSetCallback(pipe_reader_, std::bind(&onPipeCommandCompleted, _1, _2, _3, _4, _5, _6, _7));
OasisPipeWriterRef pipe_writer_ = pipeWriterOpen("/tmp/oasis-mon-req");
pipeWriterSetErrorCallback(pipe_writer_, std::bind(&onPipeCommandWriteError, _1, _2, _3, _4), nullptr);
읽기 콜백 함수입니다.
void onPipeCommandCompleted(const void *data, size_t length, int32_t width, int32_t height, int32_t stride, int32_t data_type, uint32_t flags)
{
std::string reply((const char*)data, (const char*)data+length);
Json::Value json_reply;
Json::Reader reader;
bool parsing_ok = reader.parse(reply.c_str(), json_reply);
if(!parsing_ok) {
return;
}
if(json_reply.isMember("result")) {
//결과를 확인합니다.
int32_t result = std::stoi(json_reply["result"].asString());
}
}
쓰기 오류 이벤트 콜백 함수입니다.
void DashApp::onPipeCommandWriteError(int32_t error, const void *data, size_t length, void *user)
{
}
명령 수행 프로세스에 OFFS format 명령을 전달합니다.
Json::Value json_req;
json_req["cmd"] = "format";
Json::FastWriter fastWriter;
std::string json_string = fastWriter.write(json_req);
pipeWriterWrite(pipe_writer_, json_string.c_str(), json_string.length(), 0, 0, 0, 0, 0);
명령 수행 프로세스¶
읽기 쓰기 파이프를 생성하고 각각 콜백을 등록합니다. 명령 요청 프로세스에서 사용하는 경로가 각각 바뀌어서 사용됩니다.
// 명령을 수행하고 결과를 명령 요청 프로세스에게 전달합니다.
OasisPipeWriterRef writer = pipeWriterOpen("/tmp/oasis-mon-res");
// 명령 요청 프로세스로 부터 명령 요청 메세지를 읽습니다.
OasisPipeReaderRef reader = pipeReaderOpen("/tmp/oasis-mon-req");
pipeReaderSetCallback(reader, std::bind(&onCommand, _1, _2, _3, _4, _5, _6, _7));
명령 읽는 콜백 함수입니다.
static void onCommand(const void *data, size_t length, int32_t width, int32_t height, int32_t stride, int32_t data_type, uint32_t flags)
{
if(length == 0) {
//nothing to do
return;
}
std::string cmd((const char *)data, (const char *)data+length);
Json::Value json_req;
Json::Reader reader;
bool parsing_ok = reader.parse(cmd.c_str(), json_req);
if(!parsing_ok) {
fprintf(stdout, "pipe req: json parsing error: %s\n", cmd.c_str());
continue;
}
if(json_req.isMember("cmd") == false) {
fprintf(stdout, "pipe req: \"cmd\" not found!: %s\n", cmd.c_str());
continue;
}
std::string req_cmd = json_req["cmd"].asString();
if(req_cmd == "format") {
//파일 시스템 포맷을 진행합니다.
char shell_cmd[PATH_MAX];
int32_t req_cmd_result = 0;
sprintf(shell_cmd, "/usr/sbin/mkfs.offs /dev/mmcblk0p1 /etc/offs-format.cfg 32GB_DRV");
err = runCommand(shell_cmd);
if(err) {
req_cmd_result = -err;
}
Json::Value json_reply;
json_reply["result"] = std::to_string(req_cmd_result);
json_reply["cmd"] = req_cmd;
Json::FastWriter fastWriter;
std::string json_string = fastWriter.write(json_reply);
pipeWriterWrite(writer, json_string.c_str(), json_string.length(), 0, 0, 0, 0, 0);
}
}
popen 함수를 이용하여 명령을 수행하는 함수입니다.
#define MAXLINE 4096
static int32_t runCommand(const char *shell_cmd)
{
char buff[MAXLINE];
FILE *fp;
fp = popen(shell_cmd, "r");
if(fp == NULL) {
fprintf(stderr, "\"%s\" popen error: %d(%s)\n", shell_cmd, errno, strerror(errno));
return -errno;
}
while(fgets(buff, MAXLINE, fp) != NULL) {
fprintf(stdout, "%s", buff);
fflush(stdout);
}
return (int32_t)(int8_t)pclose(fp);
}