🌐 한국어

    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);
    }