🌐 English

    Combined Recording API#

    Processes recording and snapshot events through the oasis::MediaObserver object passed when calling oasis::startRecording.

    Header File#

    OasisMedia.h

    Functions#

    RecorderRef createRecorder ( key_value_map_t & parameters )
    OasisMedia.h
    Creates a Recorder object.
    Parameters
    parameters  A key-value map required for creating a Recorder object. Refer to the Parameters section.
    Return Value
    Returns a Recorder object if successful, and returns nullptr if it fails.
    int32_t destroyRecorder ( RecorderRef recorder )
    OasisMedia.h
    Releases a Recorder object.
    Parameters
    recorder  The Recorder object to be released.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t changeRecorderParameters ( RecorderRef recorder , key_value_map_t & parameters )
    OasisMedia.h
    Changes the configuration values of a Recorder object.
    Parameters
    recorder  The Recorder object.
    parameters  The key-value map to change.
    Return Value
    • 0: Success
    • -1: Failure

    Note

    The Recorder must be in a stopped state before calling changeRecorderParameters. If it is in an active state, call stopRecording to bring it to a stopped state.

    bool recorderIsRunning ( RecorderRef recorder )
    OasisMedia.h
    Determines whether recording has started.
    Parameters
    recorder  The Recorder object.
    Return Value
    • true: The Recorder is in an operating state.
    • false: The Recorder is in a stopped state.
    bool isRecorderRecording ( RecorderRef recorder )
    OasisMedia.h
    Determines whether actual file writing is in progress after recording has started.
    Parameters
    recorder  The Recorder object.
    Return Value
    • true: The Recorder is in a state of writing recording data to a file.
    • false: The Recorder is in a state of not writing recording data to a file.
    int32_t startRecording ( RecorderRef recorder , const std::shared_ptr<MediaObserver> observer , void * user_data , bool sniffing = false )
    OasisMedia.h
    Starts recording.
    Parameters
    recorder  The Recorder object.
    observer  The recording state Observer object.
    user_data  User-defined data to be passed to the observer.
    sniffing  Set to true when operating in Sniffing mode. In Sniffing mode, recording can be started by external factors such as motion detection or event detection, and normal recording does not start.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t startRecording ( RecorderRef recorder , const std::shared_ptr<MediaObserver> observer , void * user_data , void * stream_data_header , size_t stream_data_header_size )
    OasisMedia.h
    Starts recording.
    Parameters
    recorder  The Recorder object.
    observer  The recording state Observer object.
    user_data  User-defined data to be passed to the observer.
    stream_data_header  The meta data header to be saved in the recording file.
    stream_data_header_size  The size of the meta data header to be saved in the recording file. The size is in bytes.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t startRecording ( RecorderRef recorder , const std::shared_ptr<MediaObserver> observer , void * user_data , bool sniffing , void * stream_data_header , size_t stream_data_header_size )
    OasisMedia.h
    Starts recording.
    Parameters
    recorder  The Recorder object.
    observer  The recording state Observer object.
    user_data  User-defined data to be passed to the observer.
    sniffing  Set to true when operating in Sniffing mode. In Sniffing mode, recording can be started by external factors such as motion detection or event detection, and normal recording does not start.
    stream_data_header  The meta data header to be saved in the recording file.
    stream_data_header_size  The size of the meta data header to be saved in the recording file. The size is in bytes.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t stopRecording ( RecorderRef recorder )
    OasisMedia.h
    Stops recording.
    Parameters
    recorder  The Recorder object.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t restartRecording ( RecorderRef recorder )
    OasisMedia.h
    Restarts a stopped recording. This is not supported in Sniffing mode.
    Parameters
    recorder  The Recorder object.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t startEventRecording ( RecorderRef recorder , const char * event_recording_file_path )
    OasisMedia.h
    Starts event recording. Event recording records from the video before the event occurrence by the time (seconds) specified in event-pre-recording-seconds to after the occurrence by the time (seconds) specified in event-post-recording-seconds. Whether event recording has started or ended can be known through MediaObserver::onEventRecordingStarted and MediaObserver::onEventRecordingCompleted. Event recording proceeds simultaneously with the current recording.
    Parameters
    recorder  The Recorder object.
    event_recording_file_path  The absolute path of the event recording file to be saved.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t startEventRecording ( RecorderRef recorder , const char * event_recording_file_path , void * stream_data_header , size_t stream_data_header_size )
    OasisMedia.h
    Starts event recording. Event recording records from the video before the event occurrence by the time (seconds) specified in event-pre-recording-seconds to after the occurrence by the time (seconds) specified in event-post-recording-seconds. Whether event recording has started or ended can be known through MediaObserver::onEventRecordingStarted and MediaObserver::onEventRecordingCompleted. Event recording proceeds simultaneously with the current recording.
    Parameters
    recorder  The Recorder object.
    event_recording_file_path  The absolute path of the event recording file to be saved.
    stream_data_header  The meta data header to be saved in the recording file.
    stream_data_header_size  The size of the meta data header to be saved in the recording file. The size is in bytes.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t startEventRecording ( RecorderRef recorder , const char * event_recording_file_path , void * stream_data_header , size_t stream_data_header_size , bool do_single_recording )
    OasisMedia.h
    Starts event recording. Event recording records from the video before the event occurrence by the time (seconds) specified in event-pre-recording-seconds to after the occurrence by the time (seconds) specified in event-post-recording-seconds. Whether event recording has started or ended can be known through MediaObserver::onEventRecordingStarted and MediaObserver::onEventRecordingCompleted.
    Parameters
    recorder  The Recorder object.
    event_recording_file_path  The absolute path of the event recording file to be saved.
    stream_data_header  The meta data header to be saved in the recording file.
    stream_data_header_size  The size of the meta data header to be saved in the recording file. The size is in bytes.
    do_single_recording  If true, normal recording is stopped and event recording is started. When event recording ends, normal recording is restarted.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t stopEventRecording ( RecorderRef recorder )
    OasisMedia.h
    Stops event recording.
    Parameters
    recorder  The Recorder object.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t startMotionRecording ( RecorderRef recorder , const char * event_recording_file_path , void * stream_data_header , size_t stream_data_header_size )
    OasisMedia.h
    Starts motion recording. Motion recording records from the video before the event occurrence by the time (seconds) specified in motion-pre-recording-seconds to after the occurrence by the time (seconds) specified in motion-post-recording-seconds. Whether motion recording has started or ended can be known through MediaObserver::onMotionRecordingStarted and MediaObserver::onMotionRecordingCompleted.
    Parameters
    recorder  The Recorder object.
    event_recording_file_path  The absolute path of the motion recording file to be saved.
    stream_data_header  The meta data header to be saved in the recording file.
    stream_data_header_size  The size of the meta data header to be saved in the recording file. The size is in bytes.
    Return Value
    • 0: Success
    • -1: Failure

    Note

    Motion recording is supported only in Sniffing mode.

    int32_t stopMotionRecording ( RecorderRef recorder )
    OasisMedia.h
    Stops motion recording.
    Parameters
    recorder  The Recorder object.
    Return Value
    • 0: Success
    • -1: Failure
    bool isEventOrMotionRecording ( RecorderRef recorder )
    OasisMedia.h
    Determines whether event or motion recording is in progress of actual file writing.
    Parameters
    recorder  The Recorder object.
    Return Value
    • true: The Recorder is in a state of writing recording data to a file.
    • false: The Recorder is in a state of not writing recording data to a file.
    bool isEventRecording ( RecorderRef recorder )
    OasisMedia.h
    Determines whether event recording is in progress of actual file writing.
    Parameters
    recorder  The Recorder object.
    Return Value
    • true: The Recorder is in a state of writing recording data to a file.
    • false: The Recorder is in a state of not writing recording data to a file.
    bool isMotionRecording ( RecorderRef recorder )
    OasisMedia.h
    Determines whether motion recording is in progress of actual file writing.
    Parameters
    recorder  The Recorder object.
    Return Value
    • true: The Recorder is in a state of writing recording data to a file.
    • false: The Recorder is in a state of not writing recording data to a file.
    bool isEventRunning ( RecorderRef recorder )
    OasisMedia.h
    Checks whether event recording has started.
    Parameters
    recorder  The Recorder object.
    Return Value
    • true: Event recording is in an operating state.
    • false: Event recording is in a stopped state.
    int32_t setRecordingText ( RecorderRef recorder , int32_t camera_id , text_track_id_t text_id , const std::string & text , uint64_t timestampUs = 0ull )
    OasisMedia.h
    Sets the OSD text. The OSD text is placed at the bottom left of the video.
    Parameters
    recorder  The Recorder object.
    camera_id  The camera ID of the video track where the OSD will be applied. If -1, it is applied to all video tracks.
    text_id  Specifies the OSD text type. Only kTextTrackOsd is allowed.
    text  The OSD text to record.
    timestampUs  The recording timestamp in microseconds. It is not saved in the actual recording file.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t setRecordingOverlay ( RecorderRef recorder , int32_t camera_id , const void * overlay , size_t overlay_size )
    OasisMedia.h
    Sets overlay data. This function is used when using a hardware acceleration feature instead of Oasis's setRecordingText. The overlay data structure follows the hardware acceleration engine. It may not be supported depending on the hardware.
    Parameters
    recorder  The Recorder object.
    camera_id  The camera ID of the video track where the overlay data will be applied. If -1, it is applied to all video tracks.
    overlay  The overlay data pointer.
    overlay_size  The size of the overlay data. It is in bytes.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t setRecordingOsdTextAt ( RecorderRef recorder , int32_t camera_id , int32_t x , int32_t y , const std::string & text , osd_text_flag_t flags )
    OasisMedia.h
    Records OSD text at a specific position on the video image.
    Parameters
    recorder  The Recorder object.
    camera_id  The camera ID of the video track where the overlay data will be applied. If -1, it is applied to all video tracks.
    x  The x starting position of the OSD text.
    y  The y starting position of the OSD text.
    text  The OSD text to record.
    flags  (Not used)
    Return Value
    • 0: Success
    • -1: Failure
    int32_t addRecordingVideoStreamData ( RecorderRef recorder , void * stream_data , size_t stream_data_length , uint64_t timestampUs = 0ull )
    OasisMedia.h
    Saves meta data. The user can periodically or as needed save meta data along with recording data.
    Parameters
    recorder  The Recorder object.
    stream_data  The meta data pointer. The meta data format is user-defined.
    stream_data_length  The size of the meta data. It is in bytes.
    timestampUs  The timestamp in microseconds. It is not saved in the recording file.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t enableRearCameraRecording ( RecorderRef recorder , bool enable )
    OasisMedia.h
    Stops or activates rear camera recording. The rear camera is a camera whose camera position setting key value source&lt;N>-loc was set to rear during camera device initialization via the oasis::configCameras function.
    Parameters
    recorder  The Recorder object.
    enable  If true, it is activated; if false, rear camera recording stops.
    Return Value
    • 0: Success
    • -1: Failure
    bool isRearCameraRecordingEnable ( RecorderRef recorder )
    OasisMedia.h
    Determines whether rear camera recording is activated.
    Parameters
    recorder  The Recorder object.
    Return Value
    • true: Activating
    • false: Stopping
    int32_t enableSoundRecording ( RecorderRef recorder , bool enable )
    OasisMedia.h
    Specifies whether to activate or stop sound recording. When sound recording is stopped, the sound track saves mute data.
    Parameters
    recorder  The Recorder object.
    enable  If true, it is activated; if false, mute data is saved.
    Return Value
    • 0: Success
    • -1: Failure
    bool isSoundRecordingEnabled ( RecorderRef recorder )
    OasisMedia.h
    Determines whether sound recording is activated.
    Parameters
    recorder  The Recorder object.
    Return Value
    • true: Activating
    • false: Stopping
    int32_t getCurrentRecordingFilePath ( RecorderRef recorder , std::string & file_path )
    OasisMedia.h
    Gets the file path currently being recorded.
    Parameters
    recorder  The Recorder object.
    file_path  OUT Upon success, the recording file path is saved.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t takeRecordingSnapshot ( RecorderRef recorder , uint32_t snapshot_id , int32_t camera_id , key_value_map_t & parameters )
    OasisMedia.h
    Takes a snapshot of the video currently being recorded. When snapshot data generation is complete, it delivers JPEG image data to the MediaObserver::onSnapshotCompleted callback function.
    Parameters
    recorder  The Recorder object.
    snapshot_id  Used as the snapshot_id parameter to distinguish each snapshot in the MediaObserver::onSnapshotCompleted callback function.
    camera_id  The camera device ID.
    parameters  The key-value map required for JPEG snapshot generation.
    Return Value
    • 0: Success
    • -1: Failure

    Below is the list of key-value maps.

    Key
    Default
    M
    Description
    width
    The width of the snapshot image. If "0", it equals the original video image width.
    height
    The height of the snapshot image. If "0", it equals the original video image height.
    quality
    100
     
    Specifies the JPEG image quality. The quality value must be within the range of 0~100.
    timeout
    3000
     
    The time (milliseconds) to wait until the snapshot finishes. If "0", it waits indefinitely until completion.
    osd-font-size
    12
     
    Specifies the font size. The unit is point. If the value is "0", OSD is not used.
    osd-text-color
    255,255,255
     
    The OSD text color. The color format is either "r,g,b", "rrggbb", or "aarrggbb" hexadecimal value. For example, white equals "255,255,255" or "ffffff".
    osd-use-text-color
    1
     
    If the value is "1", the OSD text color is used. If the value is "0", characters are not displayed.
    osd-use-bg-color
    0
     
    If the value is "1", the OSD text background color is used.
    osd-bg-color
    0,0,0
     
    The OSD text background color.
    osd-use-outline-color
    0
     
    If the value is "1", the text outline color is used.
    osd-outline-color
    255,255,255
     
    The text outline color.
    osd-horz-align
    center
     
    Specifies the horizontal alignment of the OSD text. Specify one of left, center, or right.
    osd-vert-align
    bottom
     
    Specifies the vertical alignment of the OSD text. Specify one of top, center, or bottom.
    osd-font-path
     
    If not specified, the system-font-path value defined during oasis::initialize is used.
    osd-use-fixed-size
    0
     
    Uses fixed-width font size characters.

    Example#

    Below is an example of recording 3 video channels and sound.

    If USE_OFFS is 1, the Oasis filesystem is used; if 0, DRIVING and EVENT folders are created and used under the /tmp folder. The file size within each folder is limited to 20MB, and only a total of 5 files are recorded. In the case of the Oasis file system, there is no limit on the number of recording files, and when the capacity is full, the oldest file is automatically overwritten.

    #define USE_OFFS 0
    

    The video codec is H264, and the audio codec uses AAC.

      //non-offs, use system fs
    #if !USE_OFFS  
      fs::offsConfigLocalFormatInfo("/tmp/DRIVING", 20*1024*1024);
      fs::offsConfigLocalFormatInfo("/tmp/EVENT", 20*1024*1024);
    #endif
    

    Initializes Oasis.

    bool offs_disabled = false;
    if(!offs_disabled) {
      parameters["offs-qsize-max"] = std::to_string(OFFS_QUEUE_SIZE_KBYTES);
      parameters["offs-overwrite-if-exist"] = "1";
      parameters["offs-cache-size"] = std::to_string(OFFS_CACHE_SIZE_KBYTES);
    } else {
      parameters["offs-disable"] = "1";
    }
    parameters["media-cache-size"] = std::to_string(MEDIA_CACHE_SIZE_KBYTES);
    //parameters["oasis-log-flags"] = std::to_string(OASIS_LOG_DEBUG/*|OASIS_LOG_ENCODE_BITRATE*/);
    
    enableLogLocalTime(true);
    
    if(oasis::initialize(parameters) < 0) {
      DLOG(DLOG_ERROR, "Oasis init failed\n");
      return -1;
    }
    

    Initializes the input and output audio devices.

    
    ////////////////////////////////////////////////////////////////////////////////////////////
    // audio
    parameters.clear();
    
    parameters["types"]="source,sink";
    parameters["path"]=SND_PATH;
    parameters["always-on"]="0";
    parameters["channels"]="2";
    parameters["aec-disabled"]="1";
    parameters["denoise-enabled"]="1";
    parameters["snd-input-channels"]="2";
    parameters["snd-input-sample-size"]="16";
    parameters["snd-input-sampling-duration-msec"]="40";
    parameters["snd-input-sampling-rate"]="48000";
    
    createAudioDevice(parameters);
    

    Configures a total of 3 camera devices.

    
    ////////////////////////////////////////////////////////////////////////////////////////////
    // sources
    parameters.clear();
    
    parameters["source-count"] = "3";
    
    parameters["source1-camera-id"] = "0";
    parameters["source1-isp-id"] = "0";
    parameters["source1-isp-wdr-mode"] = "0";
    parameters["source1-capture-format"] = "YUV420";
    parameters["source1-capture-buffers"] = "5";
    parameters["source1-fps"] = "30";
    parameters["source1-subchannel-rotation"] = "0";
    parameters["source1-loc"] = "front";
    parameters["source1-capture-resolution"] = "2160p";
    parameters["source1-sensor-config"] = "./Resource_678/VIC/2/imx678_3840x2160_ch2.cfg";
    parameters["source1-autoscene-config"] = "./Resource_678/AutoScene/autoscene_conf.cfg";
    parameters["source1-resource-dir"] = "./Resource_678/";
    
    parameters["source2-camera-id"] = "1";
    parameters["source2-isp-id"] = "0";
    parameters["source2-isp-wdr-mode"] = "0";
    parameters["source2-capture-format"] = "YUV420";
    parameters["source2-capture-buffers"] = "5";
    parameters["source2-fps"] = "30";
    parameters["source2-subchannel-rotation"] = "0";
    parameters["source2-loc"] = "right";
    parameters["source2-capture-resolution"] = "1080p";
    parameters["source2-sensor-config"] = "./Resource_tp2863/VIC/0/tp2863_1920x1080_ch0.cfg";
    parameters["source2-autoscene-config"] = "./Resource_tp2863/AutoScene/autoscene_conf.cfg";
    parameters["source2-resource-dir"] = "./Resource_tp2863/";
    
    parameters["source3-camera-id"] = "2";
    parameters["source3-isp-id"] = "0";
    parameters["source3-isp-wdr-mode"] = "0";
    parameters["source3-capture-format"] = "YUV420";
    parameters["source3-capture-buffers"] = "5";
    parameters["source3-fps"] = "30";
    parameters["source3-subchannel-rotation"] = "0";
    parameters["source3-loc"] = "left";
    parameters["source3-capture-resolution"] = "1080p";
    parameters["source3-sensor-config"] = "./Resource_tp2863/VIC/1/tp2863_1920x1080_ch1.cfg";
    parameters["source3-autoscene-config"] = "./Resource_tp2863/AutoScene/autoscene_conf.cfg";
    parameters["source3-resource-dir"] = "./Resource_tp2863/";
    
    configCameras(parameters);
    

    Defines a user-defined Observer class derived from MediaObserver.

    class MyRecordingObserver : public MediaObserver {
      public:
      virtual void onStarted(void* user_data, const char* file_path) {
        DLOG(DLOG_RECORD|DLOG_INFO, "Recording started, file path \"%s\"\r\n", file_path);
      }
    
      virtual void onStopped(void* user_data, media_report_reason_t reason, void* details) {
        DLOG(DLOG_RECORD|DLOG_INFO, "Recording stopped, reason: %d(%s)\r\n", reason, mediaReportReasonString(reason));
        if(reason != kMediaReportNoError) {
          continue_recording = false;
        }
      }
    
      virtual void onFileChanged(void* user_data, const char* new_file_path) {
        /* A (new) recording has started. */
      }
    
      virtual void onError(void* user_data, media_report_reason_t reason, void* details) {
        /* Prints the error to the console and ends the recording. */
    
        continue_recording = false;    
      }
    
      virtual void onInfo(void* user_data, MediaInfo* info) {
        /* Not used. */
      }
    
      virtual void onInfoEx(void* user_data, MediaInfoEx* info) {
        /* Prints the elapsed recording time and resource states to the console. */
      }
    
      //player paused and resumed
      virtual void onPaused(void *user_data, MediaInfo *info) {}
      virtual void onResumed(void *user_data, MediaInfo *info) {}
    
      virtual void onEventRecordingStarted(void* user_data, media_report_reason_t reason, const char* file_path) {}
      virtual void onEventRecordingCompleted(void* user_data, media_report_reason_t reason, const char* file_path) {}
      virtual void onMotionRecordingStarted(void *user_data, media_report_reason_t reason, const char *file_path) {}
      virtual void onMotionRecordingCompleted(void *user_data, media_report_reason_t reason, const char *file_path) {}
    
      virtual void queryNewFilePath(void* user_data, oasis::recording_mode_t file_type, bool rear_camera_on, bool sound_on, std::string& file_path) {
        /* Allows the new recording file path to be used as it is without modification. */
      }
    
      virtual void onSnapshotCompleted(void *user_data, uint32_t snapshot_id, int32_t camera_id, int error, const std::vector<char> &image_data, const struct timeval &timestamp) {}
    
    };
    

    Creates a recording object. It does not have to match the count and order of cameras configured in configCameras. source<N>- of configCameras and channel<N>- during recording object creation are separate. The channel<N>-camera-id value during recording object creation uses the camera device source<M> that matches source<M>-camera-id.

    ////////////////////////////////////////////////////////////////////////////////////////////
    //recorer settings
    parameters.clear();
    
    parameters["file-prefix"] =  "oasis-";
    parameters["file-extension"] = "mp4";
    parameters["file-duration-secs"] = "60";
    #if USE_OFFS
    parameters["normal-folder-path"] = "/mnt/sd/DRIVING";
    parameters["event-folder-path"] = "/mnt/sd/EVENT";
    parameters["motion-folder-path"] = "/mnt/sd/EVENT";
    #else
    parameters["normal-folder-path"] = "/tmp/DRIVING";
    parameters["event-folder-path"] = "/tmp/EVENT";
    parameters["motion-folder-path"] = "/tmp/EVENT";
    #endif
    
    parameters["event-pre-recording-seconds"] = "10";
    parameters["event-post-recording-seconds"] = "10";
    parameters["motion-pre-recording-seconds"] = "10";
    parameters["motion-post-recording-seconds"] = "30";
    parameters["disable-event-recording"] = "0";
    parameters["disable-offs-recording"] = "0";
    #if USE_OFFS
    parameters["max-files"] = "0";
    #else  
    parameters["max-files"] = "5";
    #endif  
    parameters["delete-oldest-file-on-max-files"] = "1";
    parameters["recording-size-limit-threshold-seconds"] = "1";
    parameters["report-media-info-ex"] = "1";
    
    parameters["avi-strd-size-max"] = "65536";
    parameters["mp4-udta-size-max"] = "65536";
    parameters["enable-persistent-cache"] = "0";
    parameters["recording-file-header-write-interval-secs"] = "1";
    
    parameters["snd-path"] = "hw:0,0";
    parameters["snd-input-channels"] = "2";
    parameters["snd-input-sample-size"] = "16";
    parameters["snd-input-sampling-duration-msec"] = "120";
    parameters["snd-input-sampling-rate"] = "44100";
    //parameters["snd-input-sampling-rate"] = "48000";
    
    parameters["aencoder-type"] = "aac"; //aac, raw, mp3
    parameters["aencoder-bitrate"] = "128000";
    
    parameters["osd-font-size"] = "0"; // disable (default)
    parameters["osd-font-face"] = "Consolas";
    parameters["osd-text-color"] = "255,255,255";
    parameters["osd-use-text-color"] = "1";
    parameters["osd-use-bg-color"] = "0";
    parameters["osd-bg-color"] = "0,0,0";
    parameters["osd-use-outline-color"] = "1";
    parameters["osd-outline-color"] = "255,255,255";
    parameters["osz-horz-align"] = "left";
    parameters["osd-vert-align"] = "bottom";
    parameters["osd-font-path"] = "/mnt/sd/consola.ttf";
    parameters["osd-use-fixed-size"] = "0";
    
    parameters["channel-count"] = "3";
    
    parameters["channel1-camera-id"] = "0";
    parameters["channel1-ise-id"] = "-1";
    parameters["channel1-resolution"] = "2160p";
    parameters["channel1-bitrate"] = "8000000";
    parameters["channel1-fps"] = "30";
    parameters["channel1-file-framerate"] = "30";
    parameters["channel1-vencoder-type"] = "h264";
    parameters["channel1-venc-framerate"] = "30";
    parameters["channel1-venc-keyframe-interval"] = "30";
    parameters["channel1-h264-profile"] = "high";
    parameters["channel1-h264-level"] = "level51";
    parameters["channel1-h264-enable-cabac"] = "1";
    parameters["channel1-h264-min-qp"] = "10";
    parameters["channel1-h264-max-qp"] = "31";
    parameters["channel1-h264-enable-fixqp"] = "0";
    parameters["channel1-h264-fix-iqp"] = "10";
    parameters["channel1-h264-fix-pqp"] = "20";
    parameters["channel1-media-wait-timeout-secs"] = "3";
    parameters["channel1-media-wait-timeout-notify-oneshot"] = "1";
    parameters["channel1-osd-font-size"] = "12";
    
    parameters["channel2-camera-id"] = "1";
    parameters["channel2-ise-id"] = "-1";
    parameters["channel2-resolution"] = "1080p";
    parameters["channel2-bitrate"] = "8000000";
    parameters["channel2-fps"] = "30";
    parameters["channel2-file-framerate"] = "30";
    parameters["channel2-vencoder-type"] = "h264";
    parameters["channel2-venc-framerate"] = "30";
    parameters["channel2-venc-keyframe-interval"] = "30";
    parameters["channel2-h264-profile"] = "high";
    parameters["channel2-h264-level"] = "level51";
    parameters["channel2-h264-enable-cabac"] = "1";
    parameters["channel2-h264-min-qp"] = "10";
    parameters["channel2-h264-max-qp"] = "31";
    parameters["channel2-h264-enable-fixqp"] = "0";
    parameters["channel2-h264-fix-iqp"] = "10";
    parameters["channel2-h264-fix-pqp"] = "20";
    parameters["channel2-media-wait-timeout-secs"] = "3";
    parameters["channel2-media-wait-timeout-notify-oneshot"] = "1";
    parameters["channel2-osd-font-size"] = "12";
    
    parameters["channel3-camera-id"] = "2";
    parameters["channel3-ise-id"] = "-1";
    parameters["channel3-resolution"] = "1080p";
    parameters["channel3-bitrate"] = "8000000";
    parameters["channel3-fps"] = "30";
    parameters["channel3-file-framerate"] = "30";
    parameters["channel3-vencoder-type"] = "h264";
    parameters["channel3-venc-framerate"] = "30";
    parameters["channel3-venc-keyframe-interval"] = "30";
    parameters["channel3-h264-profile"] = "high";
    parameters["channel3-h264-level"] = "level51";
    parameters["channel3-h264-enable-cabac"] = "1";
    parameters["channel3-h264-min-qp"] = "10";
    parameters["channel3-h264-max-qp"] = "31";
    parameters["channel3-h264-enable-fixqp"] = "0";
    parameters["channel3-h264-fix-iqp"] = "10";
    parameters["channel3-h264-fix-pqp"] = "20";
    parameters["channel3-media-wait-timeout-secs"] = "3";
    parameters["channel3-media-wait-timeout-notify-oneshot"] = "1";
    parameters["channel3-osd-font-size"] = "12";
    
    
    std::shared_ptr<MyRecordingObserver> recording_observer = std::make_shared<MyRecordingObserver>();
    //dumpParameters("recorder", recorder_parameters);
    
    RecorderRef recorder = createRecorder(parameters);
    if(recorder == nullptr) {
      DLOG(DLOG_ERROR, "recorder creation failed!\r\n");
      goto done;
    }
    

    Creates a timer thread to output meta data and OSD text.

    t2 = std::thread([&]() {
      time_t t;
      struct tm tm_t;
      uint64_t usec, preview_usec;
      std::string title;
      uint32_t count = 0;
    
      char stream_data[512] = { 0, };
    
      preview_usec = systemTime();
    
      do {
    
        usec = systemTime();
    
        time(&t);
        localtime_r(&t, &tm_t);
    
        if (isRecorderRecording(recorder)) {
          sprintf(stream_data, "Main %4d/%02d/%02d %02d:%02d:%02d", tm_t.tm_year + 1900, tm_t.tm_mon + 1, tm_t.tm_mday, tm_t.tm_hour, tm_t.tm_min, tm_t.tm_sec);
          addRecordingVideoStreamData(recorder, (void*)stream_data, strlen(stream_data) + 1);
        }
    
        if(/*count == 0 &&*/ isRecorderRecording(recorder)) {
          title = oasis::format("OASIS %4d/%02d/%02d %02d:%02d:%02d\n", tm_t.tm_year + 1900, tm_t.tm_mon + 1, tm_t.tm_mday, tm_t.tm_hour, tm_t.tm_min, tm_t.tm_sec);
          setRecordingText(recorder, kTextTrackOsd, title, usec);
          count++;
        }
    
        //30 msec
        usleep(40000);
    
      } while (timer_running);
    });
    

    Starts recording.

    err = startRecording(recorder, recording_observer, nullptr, false, &strd_data_header_, sizeof(strd_data_header_));
    if(err < 0) {
      DLOG(DLOG_ERROR, "start recording failed\r\n");
      goto done;
    }
    

    Below is the complete code.

    #include "OasisAPI.h"
    #include "OasisLog.h"
    #include "OasisMedia.h"
    #include "OasisFS.h"
    #include "OasisUtil.h"
    
    #include <thread>
    #include <mutex>
    #include <memory>
    #include <condition_variable>
    
    #include <signal.h>
    
    #define DLOG_THIS   0x00010000
    #define DLOG_RECORD 0x00020000
    #define DLOG_FRAME  0x00040000
    #define DLOG_TRACE  0x00080000
    
    #undef DLOG_FLAGS
    #define  DLOG_FLAGS (DLOG_FLAGS_DEFAULT|DLOG_RECORD|DLOG_TRACE|DLOG_THIS/*|DLOG_FRAME*/)
    
    #undef DLOG_TAG
    #define DLOG_TAG "RECORDER"
    
    #define OFFS_QUEUE_SIZE_KBYTES  (20*1024)
    #define OFFS_CACHE_SIZE_KBYTES  (1024)
    #define OFFS_WRITE_ALIGNMENT_BYTES  8192
    #define MEDIA_CACHE_SIZE_KBYTES (40*1024)
    
    #define USE_OFFS 0
    
    using namespace oasis;
    
    static bool timer_running = true;
    static bool continue_recording = true;
    
    static void bytesToString(size_t size, char *size_string)
    {
      if(size >= 1024*1024) {
        sprintf(size_string, "%.2fMB", (double)size/1048576);
      } else if(size >= 1024) {
        sprintf(size_string, "%.2fKB", (double)size/1024);
      } else {
        sprintf(size_string, "%dB", size);
      }
    }
    
    static uint8_t strd_data_header_[24] = {0, };
    
    class MyRecordingObserver : public MediaObserver {
      public:
      virtual void onStarted(void* user_data, const char* file_path) {
        DLOG(DLOG_RECORD|DLOG_INFO, "Recording started, file path \"%s\"\r\n", file_path);
      }
    
      virtual void onStopped(void* user_data, media_report_reason_t reason, void* details) {
        DLOG(DLOG_RECORD|DLOG_INFO, "Recording stopped, reason: %d(%s)\r\n", reason, mediaReportReasonString(reason));
        if(reason != kMediaReportNoError) {
          continue_recording = false;
        }
      }
    
      virtual void onFileChanged(void* user_data, const char* new_file_path) {
        DLOG(DLOG_RECORD|DLOG_INFO, "New file used: \"%s\"\r\n", new_file_path);
      }
    
      virtual void onError(void* user_data, media_report_reason_t reason, void* details) {
    
        if(reason == kRecordingErrorMediaDataTimeout) {
          int32_t camera_id = (intptr_t)details;
          DLOG(DLOG_RECORD|DLOG_ERROR, "Recording error, reason: %d(%s), camera<%d>\r\n", reason, mediaReportReasonString(reason), camera_id);
        } else if(reason == kRecordingErrorMediaCacheReadErrorBegin) {
          DLOG(DLOG_RECORD|DLOG_ERROR, "Recording error, reason: %d(%s) ===> stopping\r\n", reason, mediaReportReasonString(reason));
        } else if(reason == kRecordingErrorMediaCacheReadErrorEnd) {
          DLOG(DLOG_RECORD|DLOG_ERROR, "Recording error, reason: %d(%s)\r\n", reason, mediaReportReasonString(reason));
        }
    
        continue_recording = false;    
      }
    
      virtual void onInfo(void* user_data, MediaInfo* info) {
        DLOG(DLOG_RECORD, "Recording duration %lld.%06lld sec\r\n", info->durationUs / 1000000ll, info->durationUs % 1000000ll);
      }
    
      virtual void onInfoEx(void* user_data, MediaInfoEx* info) {
        dumpInfoEx(info);
      }
    
      //player paused and resumed
      virtual void onPaused(void *user_data, MediaInfo *info) {}
      virtual void onResumed(void *user_data, MediaInfo *info) {}
    
      virtual void onEventRecordingStarted(void* user_data, media_report_reason_t reason, const char* file_path) {}
      virtual void onEventRecordingCompleted(void* user_data, media_report_reason_t reason, const char* file_path) {}
      virtual void onMotionRecordingStarted(void *user_data, media_report_reason_t reason, const char *file_path) {}
      virtual void onMotionRecordingCompleted(void *user_data, media_report_reason_t reason, const char *file_path) {}
      virtual void queryNewFilePath(void* user_data, oasis::recording_mode_t file_type, bool rear_camera_on, bool sound_on, std::string& file_path) {
        // use as it is
      }
      virtual void onSnapshotCompleted(void *user_data, uint32_t snapshot_id, int32_t camera_id, int error, const std::vector<char> &image_data, const struct timeval &timestamp) {}
    
    };
    
    
    void print_usage(const char *pname)
    {
      DLOG0(DLOG_INFO, "USAGE: %s\n", pname);
    }
    
    void cancel_handler(int signum)
    {
      timer_running = false;
      continue_recording = false;
    }
    
    #if 0
    #define SND_PATH "default"
    #else
    #define SND_PATH "hw:0,0"
    #endif
    
    int main(int argc, char* argv[])
    {
      int32_t err;
      std::thread t2;
    
      oasis::key_value_map_t parameters;
    
      srand(time(NULL));
    
      signal(SIGINT, cancel_handler);
    
       ////////////////////////////////////////////////////////////////////////////////////////////
      // init
      bool offs_disabled = false;
      if(!offs_disabled) {
        parameters["offs-qsize-max"] = std::to_string(OFFS_QUEUE_SIZE_KBYTES);
        parameters["offs-overwrite-if-exist"] = "1";
        parameters["offs-cache-size"] = std::to_string(OFFS_CACHE_SIZE_KBYTES);
      } else {
        parameters["offs-disable"] = "1";
      }
      parameters["media-cache-size"] = std::to_string(MEDIA_CACHE_SIZE_KBYTES);
      //parameters["oasis-log-flags"] = std::to_string(OASIS_LOG_DEBUG/*|OASIS_LOG_ENCODE_BITRATE*/);
    
      enableLogLocalTime(true);
    
      if(oasis::initialize(parameters) < 0) {
        DLOG(DLOG_ERROR, "Oasis init failed\n");
        return -1;
      }
    
      //non-offs, use system fs
    #if !USE_OFFS  
      fs::offsConfigLocalFormatInfo("/tmp/DRIVING", 20*1024*1024);
      fs::offsConfigLocalFormatInfo("/tmp/EVENT", 20*1024*1024);
    #endif
    
      ////////////////////////////////////////////////////////////////////////////////////////////
      // audio
      parameters.clear();
    
      parameters["types"]="source,sink";
      parameters["path"]=SND_PATH;
      parameters["always-on"]="0";
      parameters["channels"]="2";
      parameters["aec-disabled"]="1";
      parameters["denoise-enabled"]="1";
      parameters["snd-input-channels"]="2";
      parameters["snd-input-sample-size"]="16";
      parameters["snd-input-sampling-duration-msec"]="40";
      parameters["snd-input-sampling-rate"]="48000";
      //parameters["snd-input-sampling-rate"]="22050";
    
      createAudioDevice(parameters);
    
      ////////////////////////////////////////////////////////////////////////////////////////////
      // sources
      parameters.clear();
    
      parameters["source-count"] = "3";
    
      parameters["source1-camera-id"] = "0";
      parameters["source1-isp-id"] = "0";
      parameters["source1-isp-wdr-mode"] = "0";
      parameters["source1-capture-format"] = "YUV420";
      parameters["source1-capture-buffers"] = "5";
      parameters["source1-fps"] = "30";
      parameters["source1-subchannel-rotation"] = "0";
      parameters["source1-loc"] = "front";
      parameters["source1-capture-resolution"] = "2160p";
      parameters["source1-sensor-config"] = "./Resource_678/VIC/2/imx678_3840x2160_ch2.cfg";
      parameters["source1-autoscene-config"] = "./Resource_678/AutoScene/autoscene_conf.cfg";
      parameters["source1-resource-dir"] = "./Resource_678/";
    
      parameters["source2-camera-id"] = "1";
      parameters["source2-isp-id"] = "0";
      parameters["source2-isp-wdr-mode"] = "0";
      parameters["source2-capture-format"] = "YUV420";
      parameters["source2-capture-buffers"] = "5";
      parameters["source2-fps"] = "30";
      parameters["source2-subchannel-rotation"] = "0";
      parameters["source2-loc"] = "right";
      parameters["source2-capture-resolution"] = "1080p";
      parameters["source2-sensor-config"] = "./Resource_tp2863/VIC/0/tp2863_1920x1080_ch0.cfg";
      parameters["source2-autoscene-config"] = "./Resource_tp2863/AutoScene/autoscene_conf.cfg";
      parameters["source2-resource-dir"] = "./Resource_tp2863/";
    
      parameters["source3-camera-id"] = "2";
      parameters["source3-isp-id"] = "0";
      parameters["source3-isp-wdr-mode"] = "0";
      parameters["source3-capture-format"] = "YUV420";
      parameters["source3-capture-buffers"] = "5";
      parameters["source3-fps"] = "30";
      parameters["source3-subchannel-rotation"] = "0";
      parameters["source3-loc"] = "left";
      parameters["source3-capture-resolution"] = "1080p";
      parameters["source3-sensor-config"] = "./Resource_tp2863/VIC/1/tp2863_1920x1080_ch1.cfg";
      parameters["source3-autoscene-config"] = "./Resource_tp2863/AutoScene/autoscene_conf.cfg";
      parameters["source3-resource-dir"] = "./Resource_tp2863/";
    
      configCameras(parameters);
    
      ////////////////////////////////////////////////////////////////////////////////////////////
      //recorer settings
      parameters.clear();
    
      parameters["file-prefix"] =  "oasis-";
      parameters["file-extension"] = "mp4";
      parameters["file-duration-secs"] = "60";
    #if USE_OFFS
      parameters["normal-folder-path"] = "/mnt/sd/DRIVING";
      parameters["event-folder-path"] = "/mnt/sd/EVENT";
      parameters["motion-folder-path"] = "/mnt/sd/EVENT";
    #else
      parameters["normal-folder-path"] = "/tmp/DRIVING";
      parameters["event-folder-path"] = "/tmp/EVENT";
      parameters["motion-folder-path"] = "/tmp/EVENT";
    #endif
    
      parameters["event-pre-recording-seconds"] = "10";
      parameters["event-post-recording-seconds"] = "10";
      parameters["motion-pre-recording-seconds"] = "10";
      parameters["motion-post-recording-seconds"] = "30";
      parameters["disable-event-recording"] = "0";
      parameters["disable-offs-recording"] = "0";
    #if USE_OFFS
      parameters["max-files"] = "0";
    #else  
      parameters["max-files"] = "5";
    #endif  
      parameters["delete-oldest-file-on-max-files"] = "1";
      parameters["recording-size-limit-threshold-seconds"] = "1";
      parameters["report-media-info-ex"] = "1";
    
      parameters["avi-strd-size-max"] = "65536";
      parameters["mp4-udta-size-max"] = "65536";
      parameters["enable-persistent-cache"] = "0";
      parameters["recording-file-header-write-interval-secs"] = "1";
    
      parameters["snd-path"] = "hw:0,0";
      parameters["snd-input-channels"] = "2";
      parameters["snd-input-sample-size"] = "16";
      parameters["snd-input-sampling-duration-msec"] = "120";
      parameters["snd-input-sampling-rate"] = "44100";
      //parameters["snd-input-sampling-rate"] = "48000";
    
      parameters["aencoder-type"] = "aac"; //aac, raw, mp3
      parameters["aencoder-bitrate"] = "128000";
    
      parameters["osd-font-size"] = "0"; // disable (default)
      parameters["osd-font-face"] = "Consolas";
      parameters["osd-text-color"] = "255,255,255";
      parameters["osd-use-text-color"] = "1";
      parameters["osd-use-bg-color"] = "0";
      parameters["osd-bg-color"] = "0,0,0";
      parameters["osd-use-outline-color"] = "1";
      parameters["osd-outline-color"] = "255,255,255";
      parameters["osz-horz-align"] = "left";
      parameters["osd-vert-align"] = "bottom";
      parameters["osd-font-path"] = "/mnt/sd/consola.ttf";
      parameters["osd-use-fixed-size"] = "0";
    
      parameters["channel-count"] = "3";
    
      parameters["channel1-camera-id"] = "0";
      parameters["channel1-ise-id"] = "-1";
      parameters["channel1-resolution"] = "2160p";
      parameters["channel1-bitrate"] = "8000000";
      parameters["channel1-fps"] = "30";
      parameters["channel1-file-framerate"] = "30";
      parameters["channel1-vencoder-type"] = "h264";
      parameters["channel1-venc-framerate"] = "30";
      parameters["channel1-venc-keyframe-interval"] = "30";
      parameters["channel1-h264-profile"] = "high";
      parameters["channel1-h264-level"] = "level51";
      parameters["channel1-h264-enable-cabac"] = "1";
      parameters["channel1-h264-min-qp"] = "10";
      parameters["channel1-h264-max-qp"] = "31";
      parameters["channel1-h264-enable-fixqp"] = "0";
      parameters["channel1-h264-fix-iqp"] = "10";
      parameters["channel1-h264-fix-pqp"] = "20";
      parameters["channel1-media-wait-timeout-secs"] = "3";
      parameters["channel1-media-wait-timeout-notify-oneshot"] = "1";
      parameters["channel1-osd-font-size"] = "12";
    
      parameters["channel2-camera-id"] = "1";
      parameters["channel2-ise-id"] = "-1";
      parameters["channel2-resolution"] = "1080p";
      parameters["channel2-bitrate"] = "8000000";
      parameters["channel2-fps"] = "30";
      parameters["channel2-file-framerate"] = "30";
      parameters["channel2-vencoder-type"] = "h264";
      parameters["channel2-venc-framerate"] = "30";
      parameters["channel2-venc-keyframe-interval"] = "30";
      parameters["channel2-h264-profile"] = "high";
      parameters["channel2-h264-level"] = "level51";
      parameters["channel2-h264-enable-cabac"] = "1";
      parameters["channel2-h264-min-qp"] = "10";
      parameters["channel2-h264-max-qp"] = "31";
      parameters["channel2-h264-enable-fixqp"] = "0";
      parameters["channel2-h264-fix-iqp"] = "10";
      parameters["channel2-h264-fix-pqp"] = "20";
      parameters["channel2-media-wait-timeout-secs"] = "3";
      parameters["channel2-media-wait-timeout-notify-oneshot"] = "1";
      parameters["channel2-osd-font-size"] = "12";
    
      parameters["channel3-camera-id"] = "2";
      parameters["channel3-ise-id"] = "-1";
      parameters["channel3-resolution"] = "1080p";
      parameters["channel3-bitrate"] = "8000000";
      parameters["channel3-fps"] = "30";
      parameters["channel3-file-framerate"] = "30";
      parameters["channel3-vencoder-type"] = "h264";
      parameters["channel3-venc-framerate"] = "30";
      parameters["channel3-venc-keyframe-interval"] = "30";
      parameters["channel3-h264-profile"] = "high";
      parameters["channel3-h264-level"] = "level51";
      parameters["channel3-h264-enable-cabac"] = "1";
      parameters["channel3-h264-min-qp"] = "10";
      parameters["channel3-h264-max-qp"] = "31";
      parameters["channel3-h264-enable-fixqp"] = "0";
      parameters["channel3-h264-fix-iqp"] = "10";
      parameters["channel3-h264-fix-pqp"] = "20";
      parameters["channel3-media-wait-timeout-secs"] = "3";
      parameters["channel3-media-wait-timeout-notify-oneshot"] = "1";
      parameters["channel3-osd-font-size"] = "12";
    
    
      std::shared_ptr<MyRecordingObserver> recording_observer = std::make_shared<MyRecordingObserver>();
      //dumpParameters("recorder", recorder_parameters);
    
      RecorderRef recorder = createRecorder(parameters);
      if(recorder == nullptr) {
        DLOG(DLOG_ERROR, "recorder creation failed!\r\n");
        goto done;
      }
    
      memset(&strd_data_header_, 0, sizeof(strd_data_header_));
    
      ////////////////////////////////////////////////////////////////////////////////////////////
      // timer thread
      t2 = std::thread([&]() {
        time_t t;
        struct tm tm_t;
        uint64_t usec, preview_usec;
        std::string title;
        uint32_t count = 0;
    
        char stream_data[512] = { 0, };
    
        preview_usec = systemTime();
    
        do {
    
          usec = systemTime();
    
          time(&t);
          localtime_r(&t, &tm_t);
    
          if (isRecorderRecording(recorder)) {
            sprintf(stream_data, "Main %4d/%02d/%02d %02d:%02d:%02d", tm_t.tm_year + 1900, tm_t.tm_mon + 1, tm_t.tm_mday, tm_t.tm_hour, tm_t.tm_min, tm_t.tm_sec);
            addRecordingVideoStreamData(recorder, (void*)stream_data, strlen(stream_data) + 1);
          }
    
          if(/*count == 0 &&*/ isRecorderRecording(recorder)) {
            title = oasis::format("OASIS %4d/%02d/%02d %02d:%02d:%02d\n", tm_t.tm_year + 1900, tm_t.tm_mon + 1, tm_t.tm_mday, tm_t.tm_hour, tm_t.tm_min, tm_t.tm_sec);
            //title += "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero.";
            setRecordingText(recorder, kTextTrackOsd, title, usec);
            count++;
          }
    
          //30 msec
          usleep(40000);
    
        } while (timer_running);
      });
    
      err = startRecording(recorder, recording_observer, nullptr, false, &strd_data_header_, sizeof(strd_data_header_));
      if(err < 0) {
        DLOG(DLOG_ERROR, "start recording failed\r\n");
        goto done;
      }
    
      printf("Ctrl+C to exit...\n");
    
      do {
        usleep(100000);
      } while (continue_recording == true);
    
    done:
    
      timer_running = false;
      if (t2.joinable()) {
        t2.join();
      }
    
      if(recorder) {
        destroyRecorder(recorder);
      }
    
    
      oasis::finalize();
    
      printf("goodbye.\n");
    
      return 0;
    }