🌐 English

    Individual Recording API#

    Processes recording and snapshot events through the oasis::MediaObserver2 object passed when calling oasis::startMultiChannelRecording.

    Header File#

    OasisMedia.h

    MediaObserver2 Interface#

    The individual channel recording component processes events and the like through a user-defined Observer object derived from MediaObserver2.

    oasis::MediaObserver2 is defined in OasisMedia.h as follows:

    class MediaObserver2 : public std::enable_shared_from_this<MediaObserver2>
    {
    public:
        MediaObserver2();
        virtual ~MediaObserver2();
    
        //recording started and stopped
        virtual void onStarted(int32_t channel_id, void *user_data, const char *file_path);
        virtual void onStopped(int32_t channel_id, void *user_data, media_report_reason_t reason, void *details);
        //recording a new file
        virtual void onFileChanged(int32_t channel_id, void *user_data, const char *new_file_path);
        virtual void onFileDeleted(int32_t camera_id, void *user_data, const char *deleted_file_path);
        virtual void onError(int32_t channel_id, void *user_data, media_report_reason_t reason, void *details);
    
        //periodic report every 1 second.
        virtual void onInfo(int32_t channel_id, void *user_data, MediaInfo *info);
        virtual void onInfoEx(int32_t channel_id, void *user_data, MediaInfoEx *info);
    
        //event recording started and completed(aborted)
        virtual void onEventRecordingStarted(int32_t channel_id, void *user_data, media_report_reason_t reason, const char *file_path);
        virtual void onEventRecordingCompleted(int32_t channel_id, void *user_data, media_report_reason_t reason, const char *file_path);
    
        //motion recording started and completed(aborted)
        virtual void onMotionRecordingStarted(int32_t channel_id, void *user_data, media_report_reason_t reason, const char *file_path);
        virtual void onMotionRecordingCompleted(int32_t channel_id, void *user_data, media_report_reason_t reason, const char *file_path);
    
        virtual void queryNewFilePaths(void *user_data, recording_mode_t file_type, bool sound_on, std::list<MultiChannelRecorderFilePath> &file_paths);
    
        virtual void onSnapshotCompleted(int32_t channel_id, void *user_data, uint32_t snapshot_id, int error, const std::vector<char> &jpeg_image_data, const struct timeval &timestamp);
    };
    

    The differences between oasis::MediaObserver2 and oasis::MediaObserver are that the individual channel ID is defined as a callback argument, and a list of structures (MultiChannelRecorderFilePath) consisting of channel information and file paths is defined as an argument for the queryNewFilePaths callback function.

    void onStarted ( int32_t channel_id , void * user_data , const char * file_path )
    OasisMedia.h
    Called after recording starts.
    Parameters
    channel_id  The channel ID number, such as 1, 2, or 3.
    user_data  The user_data parameter value received when calling startMultiChannelRecording.
    file_path  The recording file path.
    void onStopped ( int32_t channel_id , void * user_data , media_report_reason_t reason , void * details )
    OasisMedia.h
    Called after recording stops.
    Parameters
    channel_id  The channel ID number, such as 1, 2, or 3.
    user_data  The user_data parameter value received when calling startMultiChannelRecording.
    reason  A constant value indicating the reason for stopping.
    details  Detailed data corresponding to the reason for stopping. The type is defined according to the reason value.
    void onFileChanged ( int32_t channel_id , void * user_data , const char * new_file_path )
    OasisMedia.h
    Called when recording is restarted with a new file. If file-duration-secs elapses during recording or the allocated file size is exceeded, recording automatically restarts with a new file. The new file path can be changed when MediaObserver2::queryNewFilePaths is called.
    Parameters
    channel_id  The channel ID number, such as 1, 2, or 3.
    user_data  The user_data parameter value received when calling startMultiChannelRecording.
    new_file_path  The new recording file path.
    void onFileDeleted ( int32_t channel_id , void * user_data , const char * deleted_file_path )
    OasisMedia.h
    Called after the oldest file is deleted from the folder when the number of recording files is limited.
    Parameters
    channel_id  The channel ID number, such as 1, 2, or 3.
    user_data  The user_data parameter value received when calling startMultiChannelRecording.
    deleted_file_path  The path of the deleted recording file.
    void onError ( int32_t channel_id , void * user_data , media_report_reason_t reason , void * details )
    OasisMedia.h
    Called when an error occurs during recording. The user can call stopMultiChannelRecording in a separate thread to stop the recording, or restart the recording after resolving the error.
    Parameters
    channel_id  The channel ID number, such as 1, 2, or 3.
    user_data  The user_data parameter value received when calling startMultiChannelRecording.
    reason  A constant value indicating the reason for stopping.
    details  Detailed data corresponding to the reason for stopping. The type is defined according to the reason value.
    void onInfo ( int32_t channel_id , void * user_data , MediaInfo * info )
    OasisMedia.h
    Called at 1-second intervals after recording starts if report-media-info-ex is set to "0" and the Recorder object is created via createMultiChannelRecorder.
    Parameters
    channel_id  The channel ID number, such as 1, 2, or 3.
    user_data  The user_data parameter value received when calling startMultiChannelRecording.
    info  The status information. Refer to the combined recording API for the structure description.
    void onInfoEx ( int32_t channel_id , void * user_data , MediaInfoEx * info )
    OasisMedia.h
    Called at 1-second intervals after recording starts if report-media-info-ex is set to "1" and the Recorder object is created via createMultiChannelRecorder.
    Parameters
    channel_id  The channel ID number, such as 1, 2, or 3.
    user_data  The user_data parameter value received when calling startMultiChannelRecording.
    info  The status information. Refer to the combined recording API for the structure description.
    void onEventRecordingStarted ( int32_t channel_id , void * user_data , media_report_reason_t reason , const char * file_path )
    OasisMedia.h
    Called when event recording starts.
    Parameters
    channel_id  The channel ID number, such as 1, 2, or 3.
    user_data  The user_data parameter value received when calling startMultiChannelRecording.
    reason  A constant value indicating the reason generated when recording starts.
    file_path  The absolute path of the event recording file.
    void onEventRecordingCompleted ( int32_t channel_id , void * user_data , media_report_reason_t reason , const char * file_path )
    OasisMedia.h
    Called when event recording is completed.
    Parameters
    channel_id  The channel ID number, such as 1, 2, or 3.
    user_data  The user_data parameter value received when calling startMultiChannelRecording.
    reason  A constant value indicating the reason generated when recording is completed.
    file_path  The absolute path of the event recording file.
    void onMotionRecordingStarted ( int32_t channel_id , void * user_data , media_report_reason_t reason , const char * file_path )
    OasisMedia.h
    Called when motion recording starts.
    Parameters
    channel_id  The channel ID number, such as 1, 2, or 3.
    user_data  The user_data parameter value received when calling startMultiChannelRecording.
    reason  A constant value indicating the reason generated when recording starts.
    file_path  The absolute path of the motion recording file.
    void onMotionRecordingCompleted ( int32_t channel_id , void * user_data , media_report_reason_t reason , const char * file_path )
    OasisMedia.h
    Called when motion recording is completed.
    Parameters
    channel_id  The channel ID number, such as 1, 2, or 3.
    user_data  The user_data parameter value received when calling startMultiChannelRecording.
    reason  A constant value indicating the reason generated when recording is completed.
    file_path  The absolute path of the motion recording file.
    void queryNewFilePaths ( void * user_data , recording_mode_t file_type , bool sound_on , std::list<MultiChannelRecorderFilePath> & file_paths )
    OasisMedia.h
    Called to check the new recording file path before starting a new recording. The user can change and return the new recording file name or path if necessary.
    Parameters
    user_data  The user_data parameter value received when calling startMultiChannelRecording.
    file_type  Either kRecordingModeNormal(0) or kRecordingModeSniffing(1). It has the value kRecordingModeSniffing if recording started in sniffing mode.
    sound_on  true if sound is also being recorded.
    file_paths  IN OUT A list of structures containing the channel ID and the absolute path of the recording file. Automatically generated as &lt;Recording Directory>/REC_&lt;Channel Number>_&lt;Date Time>.&lt;Extension>. The application can change the absolute path of each recording file as needed.

    Below is the description of the MultiChannelRecorderFilePath structure.

    class MultiChannelRecorderFilePath
    {
    public:
        MultiChannelRecorderFilePath() : channel_id_(-1), private_(nullptr) {}
        MultiChannelRecorderFilePath(int32_t channel_id, const std::string file_path) : channel_id_(channel_id), file_path_(file_path), private_(nullptr) {}
        MultiChannelRecorderFilePath(const MultiChannelRecorderFilePath &src) {
            channel_id_ = src.channel_id_;
            file_path_ = src.file_path_;
            private_ = src.private_;
        }
        MultiChannelRecorderFilePath &operator=(const MultiChannelRecorderFilePath &src) {
            if(this != &src) {
                channel_id_ = src.channel_id_;
                file_path_ = src.file_path_;
                private_ = src.private_;
            }
            return *this;
        }
    public:
        int32_t channel_id_;
        std::string file_path_;
        void *private_; //DO NOT MODIFIY private_ on callback!!!
    };
    
    OasisMedia.h
    Member Type & Name
    Description
    int32_t channel_id_
    The channel number.
    std::string file_path_
    The absolute path of the file.
    void * private_
    A pointer used internally; it must not be modified.

    An example of the recording file list.

    Recording<1> path /tmp/DRIVING/REC_channel1_2000_06_26_01_04_23.mp4
    Recording<2> path /tmp/DRIVING/REC_channel2_2000_06_26_01_04_23.mp4
    Recording<3> path /tmp/DRIVING/REC_channel3_2000_06_26_01_04_23.mp4
    
    void onSnapshotCompleted ( int32_t channel_id , void * user_data , uint32_t snapshot_id , int error , const std::vector<char> & jpeg_image_data , const struct timeval & timestamp )
    OasisMedia.h
    Called when snapshot generation finishes or an error occurs after calling takeMultiChannelRecordingShapshot of the recording component.
    Parameters
    channel_id  The channel ID number, such as 1, 2, or 3.
    user_data  The user_data parameter value received when calling startMultiChannelRecording.
    snapshot_id  The snapshot_id value received when calling takeMultiChannelRecordingShapshot.
    error  The error value. It has the value kMediaReportNoError(0) if the snapshot succeeds.
    jpeg_image_data  The JPEG file data generated by the snapshot. Valid only when error is 0. The user can save this data to a file in a separate thread.
    timestamp  The timestamp at the time of snapshot generation.

    Functions#

    MultiChannelRecorderRef createMultiChannelRecorder ( key_value_map_t & parameters )
    OasisMedia.h
    Creates a MultiChannelRecorder object.
    Parameters
    parameters  The key-value map required for creating the MultiChannelRecorder object. Refer to the Parameters section.
    Return Value
    Returns the MultiChannelRecorder object on success, and returns nullptr on failure.
    int32_t destroyMultiChannelRecorder ( MultiChannelRecorderRef multi_channel_recorder )
    OasisMedia.h
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object to release.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t changeMultiChannelRecorderParameters ( MultiChannelRecorderRef multi_channel_recorder , key_value_map_t & parameters )
    OasisMedia.h
    Modifies the configuration settings of the MultiChannelRecorder object.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    parameters  The key-value map to modify.
    Return Value
    • 0: Success
    • -1: Failure

    Note

    The MultiChannelRecorder must be in a stopped state before calling changeMultiChannelRecorderParameters. If it is in an active state, call stopMultiChannelRecording to put it in a stopped state.

    bool multiChannelRecorderIsRunning ( MultiChannelRecorderRef multi_channel_recorder )
    OasisMedia.h
    Determines whether recording is running. Returns true after starting the MultiChannelRecorder object.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    Return Value
    • true: MultiChannelRecorder is in a running state.
    • false: MultiChannelRecorder is in a stopped state.
    bool isMultiChannelRecorderRecording ( MultiChannelRecorderRef multi_channel_recorder )
    OasisMedia.h
    Determines whether recording is actively writing to a file.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    Return Value
    • true: MultiChannelRecorder is in a state of writing recording data to a file.
    • false: MultiChannelRecorder is in a state of not writing recording data to a file.
    bool isMultiChannelRecorderRecording ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id )
    OasisMedia.h
    Verifies whether recording file writing is progressing per channel.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    Return Value
    • true: MultiChannelRecorder is writing the specified channel's recording data to a file.
    • false: MultiChannelRecorder is not writing the specified channel's recording data to a file.
    int32_t startMultiChannelRecording ( MultiChannelRecorderRef multi_channel_recorder , const std::shared_ptr<MediaObserver2> & observer , void * user_data , bool sniffing , void * stream_data_header , size_t stream_data_header_size )
    OasisMedia.h
    Starts recording.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    observer  The recording status Observer object.
    user_data  The user-defined data to be passed to the observer.
    sniffing  Set to true to operate 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. If not used, specify nullptr.
    stream_data_header_size  The meta data header size to be saved in the recording file. The size is measured in bytes.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t stopMultiChannelRecording ( MultiChannelRecorderRef multi_channel_recorder )
    OasisMedia.h
    Stops recording.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t restartMutiChannelRecording ( MultiChannelRecorderRef multi_channel_recorder )
    OasisMedia.h
    Restarts stopped recording. Not supported in Sniffing mode.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t startMultiChannelEventRecording ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id , const char * event_recording_file_path , void * stream_data_header , size_t stream_data_header_size , bool is_type_of_motion )
    OasisMedia.h
    Starts event or motion recording for the specified channel. Event recording records from the video prior to the event occurrence by the time (seconds) specified in event-pre-recording-seconds to the video after the occurrence by the time (seconds) specified in event-post-recording-seconds. The start and completion of event recording can be checked with MediaObserver2::onEventRecordingStarted and MediaObserver2::onEventRecordingCompleted. Event recording proceeds simultaneously with the current recording.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    event_recording_file_path  The absolute path of the event or motion recording file to be saved.
    stream_data_header  The meta data header to be saved in the recording file. If not used, specify nullptr.
    stream_data_header_size  The meta data header size to be saved in the recording file. The size is measured in bytes.
    is_type_of_motion  Proceeds with motion recording if true. Proceeds with event recording if false. The location where the recording file will be saved is set to the event path or motion recording path specified when creating the MultiChannelRecorder.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t startMultiChannelEventRecording ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id , const char * event_recording_file_path , void * stream_data_header , size_t stream_data_header_size , bool is_type_of_motion , bool do_single_recording )
    OasisMedia.h
    Starts event or motion recording for the specified channel. Event recording records from the video prior to the event occurrence by the time (seconds) specified in event-pre-recording-seconds to the video after the occurrence by the time (seconds) specified in event-post-recording-seconds. The start and completion of event recording can be checked with MediaObserver2::onEventRecordingStarted and MediaObserver2::onEventRecordingCompleted.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    event_recording_file_path  The absolute path of the event or motion recording file to be saved.
    stream_data_header  The meta data header to be saved in the recording file. If not used, specify nullptr.
    stream_data_header_size  The meta data header size to be saved in the recording file. The size is measured in bytes.
    is_type_of_motion  Proceeds with motion recording if true. Proceeds with event recording if false. The location where the recording file will be saved is set to the event path or motion recording path specified when creating the MultiChannelRecorder.
    do_single_recording  If true, it stops normal recording and starts event recording. Upon completion of event recording, normal recording resumes.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t stopMultiChannelEventRecording ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id , bool is_type_of_motion )
    OasisMedia.h
    Stops event or motion recording for the specified channel.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    is_type_of_motion  Stops motion recording if true. Stops event recording if false.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t startMultiChannelEventRecording ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id , 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 for the specified channel. Event recording records from the video prior to the event occurrence by the time (seconds) specified in event-pre-recording-seconds to the video after the occurrence by the time (seconds) specified in event-post-recording-seconds. The start and completion of event recording can be checked with MediaObserver2::onEventRecordingStarted and MediaObserver2::onEventRecordingCompleted.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    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. If not used, specify nullptr.
    stream_data_header_size  The meta data header size to be saved in the recording file. The size is measured in bytes.
    do_single_recording  If true, it stops normal recording and starts event recording. Upon completion of event recording, normal recording resumes.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t stopMultiChannelEventRecording ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id )
    OasisMedia.h
    Stops event recording for the specified channel.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t startMultiChannelEventRecording ( MultiChannelRecorderRef multi_channel_recorder , const std::list<MultiChannelRecorderFilePath> & file_paths , void * stream_data_header , size_t stream_data_header_size , bool do_single_recording )
    OasisMedia.h
    Starts event recording for all channels.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    file_paths  The list of event recording files. Each entry includes the channel number and the absolute path of the recording file.
    stream_data_header  The meta data header to be saved in the recording file. If not used, specify nullptr.
    stream_data_header_size  The meta data header size to be saved in the recording file. The size is measured in bytes.
    do_single_recording  If true, it stops normal recording and starts event recording. Upon completion of event recording, normal recording resumes.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t stopMultiChannelEventRecording ( MultiChannelRecorderRef multi_channel_recorder )
    OasisMedia.h
    Stops event recording for all channels.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    Return Value
    • 0: Success
    • -1: Failure
    bool isMultiChannelEventRunning ( MultiChannelRecorderRef multi_channel_recorder )
    OasisMedia.h
    Verifies whether event recording has started.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    Return Value
    • true: Event recording has started.
    • false: Event recording has not started.
    bool isMultiChannelEventRecording ( MultiChannelRecorderRef multi_channel_recorder )
    OasisMedia.h
    Verifies whether file writing is in progress with event recording.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    Return Value
    • true: Event recording file writing is in progress.
    • false: Event recording file writing is not in progress.
    int32_t startMultiChannelMotionRecording ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id , const char * event_recording_file_path , void * stream_data_header , size_t stream_data_header_size )
    OasisMedia.h
    Starts motion recording for the specified channel. Motion recording records from the video prior to the event occurrence by the time (seconds) specified in motion-pre-recording-seconds to the video after the occurrence by the time (seconds) specified in motion-post-recording-seconds. The start and completion of motion recording can be checked with MediaObserver2::onMotionRecordingStarted and MediaObserver2::onMotionRecordingCompleted.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    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. If not used, specify nullptr.
    stream_data_header_size  The meta data header size to be saved in the recording file. The size is measured in bytes.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t stopMultiChannelMotionRecording ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id )
    OasisMedia.h
    Stops motion recording for the specified channel.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t startMultiChannelMotionRecording ( MultiChannelRecorderRef multi_channel_recorder , const std::list<MultiChannelRecorderFilePath> & file_paths , void * stream_data_header , size_t stream_data_header_size , bool stop_current_event_recording )
    OasisMedia.h
    Starts motion recording for all channels.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    file_paths  The list of motion recording files. Each entry includes the channel number and the absolute path of the recording file.
    stream_data_header  The meta data header to be saved in the recording file. If not used, specify nullptr.
    stream_data_header_size  The meta data header size to be saved in the recording file. The size is measured in bytes.
    stop_current_event_recording  If true and current event recording is in progress, it stops the event recording.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t stopMultiChannelMotionRecording ( MultiChannelRecorderRef multi_channel_recorder )
    OasisMedia.h
    Stops motion recording for all channels.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    Return Value
    • 0: Success
    • -1: Failure
    bool isMultiChannelMotionRecording ( MultiChannelRecorderRef multi_channel_recorder )
    OasisMedia.h
    Verifies whether motion recording for all channels is actively writing to a file.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    Return Value
    • true: Writing to a file after motion recording has started.
    • false: Not writing to a file after motion recording has started.
    bool isMultiChannelEventOrMotionRecording ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id )
    OasisMedia.h
    Verifies whether event or motion recording for the specified channel has started and is actively writing to a file.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    Return Value
    • true: Event or motion recording file writing is in progress.
    • false: Event or motion recording file writing is not in progress.
    bool isMultiChannelEventRecording ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id )
    OasisMedia.h
    Verifies whether event recording for the specified channel has started and is actively writing to a file.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    Return Value
    • true: Writing to a file after event recording has started.
    • false: Not writing to a file after event recording has started.
    bool isMultiChannelMotionRecording ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id )
    OasisMedia.h
    Verifies whether motion recording for the specified channel has started and is actively writing to a file.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    Return Value
    • true: Writing to a file after motion recording has started.
    • false: Not writing to a file after motion recording has started.
    bool isMultiChannelEventRunning ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id )
    OasisMedia.h
    Verifies whether event recording for the specified channel has started.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    Return Value
    • true: Event recording has started.
    • false: Event recording has not started.
    int32_t setMultiChannelRecordingText ( MultiChannelRecorderRef multi_channel_recorder , text_track_id_t text_id , const std::string & text , uint64_t timestampUs = 0ull )
    OasisMedia.h
    Sets OSD text. OSD text is placed at the bottom left of the video.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    text_id  Specifies the OSD text type. Only kTextTrackOsd is allowed.
    text  The OSD text to record.
    timestampUs  The recording timestamp, measured in microseconds. It is not saved in the actual recording file.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t setMultiChannelRecordingText ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id , text_track_id_t text_id , const std::string & text , uint64_t timestampUs = 0ull )
    OasisMedia.h
    Sets OSD text on the specified channel. OSD text is placed at the bottom left of the video.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3. If -1, it applies to all video channels.
    text_id  Specifies the OSD text type. Only kTextTrackOsd is allowed.
    text  The OSD text to record.
    timestampUs  The recording timestamp, measured in microseconds. It is not saved in the actual recording file.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t setMultiChannelRecordingOsdTextAt ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id , int32_t x , int32_t y , const std::string & osd_text , osd_text_flag_t flags )
    OasisMedia.h
    Records OSD text at a specific position on the video image for the specified channel.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3. If -1, it applies to all video channels.
    x  The starting x position of the OSD text.
    y  The starting y position of the OSD text.
    osd_text  The OSD text to record.
    flags  (Not used)
    Return Value
    • 0: Success
    • -1: Failure
    int32_t addMultiChannelRecordingVideoStreamData ( MultiChannelRecorderRef multi_channel_recorder , void * stream_data , size_t stream_data_length , uint64_t timestampUs = 0ull )
    OasisMedia.h
    Saves meta data. The user can save meta data along with the recording data periodically or as needed.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    stream_data  The meta data pointer. The user defines the meta data format.
    stream_data_length  The meta data size. Measured in bytes.
    timestampUs  The timestamp, measured in microseconds. It is not saved in the recording file.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t enableSoundOfMultiChannelRecording ( MultiChannelRecorderRef multi_channel_recorder , int channel_id , bool enable )
    OasisMedia.h
    Specifies whether to enable or disable sound recording. When sound recording is disabled, silence data is stored in the sound track.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3. If -1, it applies to all video channels.
    enable  It is enabled if true, and silence data is stored if false.
    Return Value
    • 0: Success
    • -1: Failure
    bool isSoundOfMultiChannelRecordingEnabled ( MultiChannelRecorderRef multi_channel_recorder , int channel_id )
    OasisMedia.h
    Determines whether sound recording is enabled.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    Return Value
    • true: Currently enabled
    • false: Currently disabled
    int32_t getCurrentMultiChannelRecordingFilePath ( MultiChannelRecorderRef multi_channel_recorder , int32_t channel_id , std::string & file_path )
    OasisMedia.h
    Obtains the currently recording file path for the specified channel.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    channel_id  The channel ID number, such as 1, 2, or 3.
    file_path  OUT The recording file path is saved upon success.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t takeMultiChannelRecordingShapshot ( MultiChannelRecorderRef multi_channel_recorder , uint32_t snapshot_id , int32_t channel_id , key_value_map_t & parameters )
    OasisMedia.h
    Takes a video snapshot during current recording. When snapshot data generation is completed, it passes JPEG image data to the MediaObserver2::onSnapshotCompleted callback function.
    Parameters
    multi_channel_recorder  The MultiChannelRecorder object.
    snapshot_id  Used as the snapshot_id parameter to distinguish each snapshot in the MediaObserver2::onSnapshotCompleted callback function.
    channel_id  The channel ID number, such as 1, 2, or 3.
    parameters  The key-value map required for generating a JPEG snapshot. Refer to takeRecordingSnapshot, the combined recording API, for the parameters.
    Return Value
    • 0: Success
    • -1: Failure

    Example#

    Below is an example of recording 3 video channels and sound into individual files per channel.

    If USE_OFFS is 1, the Oasis file system is used, and 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 15 files in total are recorded. In the case of the Oasis file system, there is no limit to the number of recording files, and when the capacity is full, it automatically overwrites the oldest files.

    #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 oasis::MediaObserver2 
    {
    public:
      MyRecordingObserver() {}
      virtual ~MyRecordingObserver() {}
    
      //recording started and stopped
      virtual void onStarted(int32_t channel_id, void *user_data, const char *file_path) {
        DLOG(DLOG_THIS, "Recording<%d> started, file path \"%s\"\r\n", channel_id, file_path);
      }
      virtual void onStopped(int32_t channel_id, void *user_data, media_report_reason_t reason, void *details) {
        DLOG(DLOG_THIS, "Recording%d> stopped, reason: %d(%s)\r\n", channel_id, reason, mediaReportReasonString(reason));
        if(reason != kMediaReportNoError) {
          continue_recording = false;
        }    
      }
      //recording a new file
      virtual void onFileChanged(int32_t channel_id, void *user_data, const char *new_file_path) {
        DLOG(DLOG_THIS, "Recording<%d> new file used: \"%s\"\r\n", channel_id, new_file_path);
      }
      virtual void onError(int32_t channel_id, void *user_data, media_report_reason_t reason, void *details) {
        if(reason == kRecordingErrorMediaDataTimeout) {
          int32_t camera_id = (intptr_t)details;
          DLOG(DLOG_ERROR, "Recording<%d> error, reason: %d(%s), camera<%d>\r\n", channel_id, reason, mediaReportReasonString(reason), camera_id);
        } else if(reason == kRecordingErrorMediaCacheReadErrorBegin) {
          DLOG(DLOG_ERROR, "Recording<%d> error, reason: %d(%s) ===> stopping!!!\r\n", channel_id, reason, mediaReportReasonString(reason));
        } else if(reason == kRecordingErrorMediaCacheReadErrorEnd) {
          DLOG(DLOG_ERROR, "Recording<%d> error, reason: %d(%s)\r\n", channel_id, reason, mediaReportReasonString(reason));
        }    
        continue_recording = false;    
      }
    
      //periodic report every 1 second.
      virtual void onInfo(int32_t channel_id, void *user_data, MediaInfo *info) {
        DLOG(DLOG_THIS, "Recording<%d> duration %lld.%06lld sec\r\n", channel_id, info->durationUs / 1000000ll, info->durationUs % 1000000ll);    
      }
      virtual void onInfoEx(int32_t channel_id, void *user_data, MediaInfoEx *info) {
    #if 0 
        int h, m, s, u;
        char normal_qsize[128], event_qsize[128], in_size[128], out_size[128], cache_in_size[128];
        char video1_size[128], video2_size[128], meta_size[128], audio_size[128], file_size[128];
        parseUsec(info->durationUs, h, m, s, u);
    
        TRACE0("Recording<%d> duration \033[33m%02d:%02d:%02d.%06d\033[0m, wq#%d(%d), eq#%d(%d), meq#%d(%d), nohits#%u, mb.avail#%d/%d (free mem %.3fMB, cpu %.2f%%)\r\n", channel_id, h, m, s, u, info->writerStat.curSamples, info->writerStat.maxSamples, info->timeshiftStat.curSamples, info->timeshiftStat.maxSamples, info->writerStat.motionStat.curSamples, info->writerStat.motionStat.maxSamples, info->mediaCacheStat.nohits_, info->mediaCacheStat.free_buffer_count_, info->mediaCacheStat.total_buffer_count_, (double)oasis::getFreeMemorySize()/1024.0/1024.0, getCPUUsage());
    
        //offs state
        bytesToString(info->offsStat.qNormalSize, normal_qsize);
        bytesToString(info->offsStat.qEventSize, event_qsize);
    
        bytesToString(info->offsStat.inSize, in_size);
        bytesToString(info->offsStat.outSize, out_size);
    
        bytesToString(info->mediaCacheStat.in_size_, cache_in_size);
    
    
        TRACE0("    cache: during %d msec, in %s\r\n", info->mediaCacheStat.check_duration_, cache_in_size);
        TRACE0("    offs: n#%d, e#%d, nz#%s, ez#%s, during %d msec: in %s out %s elapsed %d msec \r\n", info->offsStat.qNormalCount, info->offsStat.qEventCount, normal_qsize, event_qsize, info->offsStat.checkDuration, in_size, out_size, info->offsStat.elapsedSum);
    
        //TRACE0("    cache: hits#%u, nohits#%u, free#%u, gets#%u, puts#%u\r\n", info->mediaCacheStat.hits_, info->mediaCacheStat.nohits_, info->mediaCacheStat.free_buffer_count_, info->mediaCacheStat.get_buffer_count_, info->mediaCacheStat.put_buffer_count_);
    
        //print recording stat in details
        bytesToString(info->writerStat.video1Length, video1_size);
        bytesToString(info->writerStat.video2Length, video2_size);
        bytesToString(info->writerStat.metaLength, meta_size);
        bytesToString(info->writerStat.audioLength, audio_size);
        bytesToString(info->writerStat.fileLength, file_size);
        TRACE0("    %s: video1 %s, video2 %s, meta %s, audio %s, file %s\n", info->sniffing?"sniffing":"recording", video1_size, video2_size, meta_size, audio_size, file_size);
    
        if(info->writerStat.motionStat.recording) {
          bytesToString(info->writerStat.motionStat.video1Length, video1_size);
          bytesToString(info->writerStat.motionStat.video2Length, video2_size);
          bytesToString(info->writerStat.motionStat.metaLength, meta_size);
          bytesToString(info->writerStat.motionStat.audioLength, audio_size);
          bytesToString(info->writerStat.motionStat.fileLength, file_size);
          TRACE0("    motion: video1 %s, video2 %s, meta %s, audio %s, file %s\n", video1_size, video2_size, meta_size, audio_size, file_size);
        }
    
        if(info->timeshiftStat.recording) {
          bytesToString(info->timeshiftStat.video1Length, video1_size);
          bytesToString(info->timeshiftStat.video2Length, video2_size);
          bytesToString(info->timeshiftStat.metaLength, meta_size);
          bytesToString(info->timeshiftStat.audioLength, audio_size);
          bytesToString(info->timeshiftStat.fileLength, file_size);
          TRACE0("    event: video1 %s, video2 %s, meta %s, audio %s, file %s\n", video1_size, video2_size, meta_size, audio_size, file_size);
        }
    #endif
      }
    
      //event recording started and completed(aborted)
      virtual void onEventRecordingStarted(int32_t channel_id, void *user_data, media_report_reason_t reason, const char *file_path) {
        DLOG(DLOG_THIS, "Event<%d> Recording started @ \"%s\" (reason: %d).\r\n", channel_id, file_path, reason);
      }
      virtual void onEventRecordingCompleted(int32_t channel_id, void *user_data, media_report_reason_t reason, const char *file_path) {
        DLOG(DLOG_THIS, "Event<%d> Recording completed @ \"%s\" (reason: %d).\r\n", channel_id, file_path, reason);
      }
    
      //motion recording started and completed(aborted)
      virtual void onMotionRecordingStarted(int32_t channel_id, void *user_data, media_report_reason_t reason, const char *file_path) {
    
      }
      virtual void onMotionRecordingCompleted(int32_t channel_id, void *user_data, media_report_reason_t reason, const char *file_path) {
    
      }
    
      virtual void queryNewFilePaths(void *user_data, recording_mode_t file_type, bool sound_on, std::list<MultiChannelRecorderFilePath> &file_paths) {
        DLOG(DLOG_THIS, "queryNewFilePath: mode: %d, sound on %d:\n", file_type, sound_on);
        for(auto it = file_paths.begin(); it != file_paths.end(); it++) {
          DLOG(DLOG_THIS, "     Recording<%d> path %s\n", (*it).channel_id_, (*it).file_path_.c_str());
        }
      }
    
      virtual void onSnapshotCompleted(int32_t channel_id, void *user_data, uint32_t snapshot_id, int error, const std::vector<char> &jpeg_image_data, const struct timeval &timestamp) {
        DLOG(DLOG_THIS, "Snapshot<%d> completed: id %d, error %d, size %zd bytes @ %d sec\n", channel_id, snapshot_id, error, jpeg_image_data.size(), timestamp.tv_sec);
      }
    
    };
    
    
    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);
    
      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";
    
      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"] = "15";
    #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["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["osd-horz-align"] = "left";
      parameters["osd-vert-align"] = "bottom";
      parameters["osd-font-path"] = "/mnt/flash/leipzig/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>();
    
      RecorderRef recorder = createMultiChannelRecorder(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 (isMultiChannelRecorderRecording(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);
            addMultiChannelRecordingVideoStreamData(recorder, (void*)stream_data, strlen(stream_data) + 1);
          }
    
          if(isMultiChannelRecorderRecording(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);
            setMultiChannelRecordingText(recorder, kTextTrackOsd, title, usec);
            count++;
          }
    
          //40 msec
          usleep(40000);
    
        } while (timer_running);
      });
    
      err = startMultiChannelRecording(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) {
        destroyMultiChannelRecorder(recorder);
      }
    
    
      oasis::finalize();
    
      printf("goodbye.\n");
    
      return 0;
    }