🌐 English

    Snapshot API#

    Apart from takeRecordingSnapshot provided by the recording component, this API captures camera images directly.

    The snapshot API provides both Non-blocking and Blocking methods.

    • By creating a Photographer object and using the PhotographerObserver interface, you can continuously generate capture files.
    • By calling the takePicture function and waiting until the snapshot is complete, you can generate a single capture file.

    Header File#

    OasisMedia.h

    Blocking Functions#

    Generates snapshot data using a Blocking method. It waits until the snapshot is complete or a timeout occurs.

    int32_t takePicture ( int32_t camera_id , int32_t quality , int32_t width , int32_t height , int32_t wait_timeout , const char * osd_horz_align , int32_t osd_vert_align , const char * osd_string , uint32_t text_color , bool use_outline_color , uint32_t outline_color , int32_t font_point_size , const char * font_path , std::vector<char> & image_data , struct timeval * timestmap = nullptr )
    OasisMedia.h
    Parameters
    camera_id  The camera ID configured in configCameras.
    quality  The JPEG image quality. Specify a value between 0 and 100.
    width  The width of the JPEG image to save. If "0", the image width configured for the camera sensor is used.
    height  The height of the JPEG image to save. If "0", the image height configured for the camera sensor is used.
    wait_timeout  The maximum time to wait until the snapshot is generated. If "0", it waits indefinitely.
    osd_horz_align  The horizontal alignment of the OSD text. Specify one value among left, center, right.
    osd_vert_align  The vertical alignment of the OSD text. Specify one value among top, vcenter, bottom.
    osd_string  The OSD text. If nullptr or an empty string is specified, the OSD text is not displayed.
    text_color  The OSD text color. It has the format 0xrrggbb.
    use_outline_color  Specifies whether to apply an outline color to the OSD text characters. If true, the outline is displayed with the outline_color.
    outline_color  The outline color of the OSD text characters. It has the format 0xrrggbb.
    font_point_size  The OSD text size. Measured in points.
    font_path  The absolute path of the OSD text font.
    image_data  OUT The JPEG image data generated by the capture.
    timestmap  OUT The time value at the time of capture generation is stored here. If a nullptr value is specified, time information is not stored.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t takePicture ( int32_t camera_id , key_value_map_t & parameters , std::vector<char> & image_data , struct timeval * timestmap = nullptr )
    OasisMedia.h
    Parameters
    camera_id  The camera ID configured in configCameras.
    parameters  The key-value map required for snapshot generation.
    image_data  OUT The JPEG image data generated by the capture.
    timestmap  OUT The time value at the time of capture generation is stored here. If a nullptr value is specified, time information is not stored.
    Return Value
    • 0: Success
    • -1: Failure

    The key-value map required for snapshot generation is as follows:

    Key
    Default
    M
    Description
    camera-id
    The camera device ID configured in configCameras.
    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 to 100.
    timeout
    3000
     
    The time (in milliseconds) to wait until the snapshot is finished. If "0", it waits indefinitely until completed.
    drop-frame-count
    0
     
    The number of frames to drop before taking the snapshot.
    snapshot-use-sw-encoder
    0
     
    Uses the SW JPEG encoder instead of the HW JPEG encoder.
    osd
    The OSD text.
    osd-font-size
    12
     
    The font size. Measured in points. If the value is "0", OSD is not applied.
    osd-text-color
    255,255,255
     
    The OSD text color. The color format is "r,g,b" or a "rrggbb" or "aarrggbb" hexadecimal value. For example, white is like "255,255,255" or "ffffff".
    osd-use-outline-color
    0
     
    Uses the character outline color if the value is "1".
    osd-outline-color
    255,255,255
     
    The character outline color.
    osd-horz-align
    left
     
    Specifies one of the values left, center, right.
    osd-vert-align
    bottom
     
    Specifies one of the values top, vcenter, bottom.
    osd-font-path
     
    If not specified, the system-font-path value defined during oasis::initialize is used.

    When generating a JPEG image, the following EXIF tagging parameters can be specified:

    Key
    Default
    M
    Description
    exif-IFD0.DateTime
     
    The JPEG recent modification date and time string for JPEG EXIF tagging. It is in a format like "2023:02:23 11:06:03".
    exif-IFD0.Software
     
    The software name that generated the JPEG image for JPEG EXIF tagging.
    exif-EXIF.ExifImageWidth
     
    The width value for JPEG EXIF tagging.
    exif-EXIF.ExifImageHeight
     
    The height value for JPEG EXIF tagging.
    exif-EXIF.ImageUniqueID
     
    The unique ID of the image for JPEG EXIF tagging. Specified by the user for convenience.
    exif-EXIF.DateTimeOriginal
     
    The original creation date and time string for JPEG EXIF tagging. It is in a format like "2023:02:23 11:06:03".
    exif-EXIF.DateTimeDigitized
     
    The date and time string when the image was scanned or processed for JPEG EXIF tagging. It is in a format like "2023:02:23 11:06:03".
    exif-EXIF.MakerNote
     
    The manufacturer note string for JPEG EXIF tagging.

    Non-Blocking Functions#

    The user creates a Photographer object using createPhotographer. After starting it with startPhotographer, photographerGeneratePicture is called whenever a snapshot is required. To finish using the Photographer, call stopPhotographer.

    PhotographerObserver Interface#

    When calling createPhotographer, a user interface object defining PhotographerObserver as a base class is passed as a parameter. Subsequently, snapshot tasks are executed via callback functions.

    class PhotographerObserver : public std::enable_shared_from_this<PhotographerObserver>
    {
    public:
      PhotographerObserver();
      virtual ~PhotographerObserver();
    
      virtual void onCameraSensorMetaData(int32_t camera_id, const CameraSensorMetaData &metadata);
      virtual void onIspMetaData(int32_t camera_id, const IspMetaData &metadata);
    
      virtual void onCaptureImageAvailable(bool subchannel_image);
      virtual void onImageDataCompleted(const key_value_map_t &parameters, bool subchannel_image, int32_t width, int32_t height, int32_t format, const std::vector<char> &data);
      virtual void onImageDataCompletedWithError(const key_value_map_t &parameters, bool subchannel_image, int32_t error);
    };
    

    Note

    onCameraSensorMetaData and onIspMetaData apply only to Raspberry Pi.

    void onCaptureImageAvailable ( bool subchannel_image )
    OasisMedia.h
    Notifies that the image to capture is ready. This can be called continuously. Snapshots can be generated after the initial notification.
    Parameters
    subchannel_image  If false, it means the main channel image is ready. If true, it means the subchannel image is ready. Depending on the camera sensor device, a subchannel image may also be generated together.
    void onImageDataCompleted ( const key_value_map_t & parameters , bool subchannel_image , int32_t width , int32_t height , int32_t format , const std::vector<char> & data )
    OasisMedia.h
    Notifies that the JPEG captured image data has been generated as a result of calling photographerGeneratePicture.
    Parameters
    parameters  The key-value map passed as a parameter to photographerGeneratePicture.
    subchannel_image  If false, it indicates main channel image data. If true, it is subchannel image data.
    width  The width of the snapshot image.
    height  The height of the snapshot image.
    format  The value kImageTypeJpeg(0).
    data  The JPEG image data.
    void onImageDataCompletedWithError ( const key_value_map_t & parameters , bool subchannel_image , int32_t error )
    OasisMedia.h
    Notifies that an error occurred as a result of calling photographerGeneratePicture.
    Parameters
    parameters  The key-value map passed as a parameter to photographerGeneratePicture.
    subchannel_image  If false, it indicates main channel image data. If true, it is subchannel image data.
    error  The error value (-1).

    Photographer API#

    PhotographerRef createPhotographer ( int32_t camera_id , key_value_map_t & parameters , const std::shared_ptr<PhotographerObserver> & observer )
    OasisMedia.h
    Creates a Photographer object.
    Parameters
    camera_id  The camera device ID configured in configCameras.
    parameters  The key-value map required to create the Photographer object.
    observer  A user-defined observer object derived from PhotographerObserver.
    Return Value
    Returns a PhotographerRef object on success. Returns nullptr on failure.
    int32_t destroyPhotographer ( PhotographerRef photographer )
    OasisMedia.h
    Releases the Photographer object.
    Parameters
    photographer  The Photographer object.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t startPhotographer ( PhotographerRef photographer )
    OasisMedia.h
    Starts the Photographer object.
    Parameters
    photographer  The Photographer object.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t stopPhotographer ( PhotographerRef photographer )
    OasisMedia.h
    Stops the Photographer object.
    Parameters
    photographer  The Photographer object.
    Return Value
    • 0: Success
    • -1: Failure
    bool isPhotographerRunning ( PhotographerRef photographer )
    OasisMedia.h
    Determines whether the Photographer object is in a started state.
    Parameters
    photographer  The Photographer object.
    Return Value
    • true: Started state.
    • false: Stopped state.
    int32_t photographerGeneratePicture ( PhotographerRef photographer , key_value_map_t & parameters , bool subchannel_image , const uint8_t * exif_user_data = nullptr , size_t exif_user_data_length = 0 )
    OasisMedia.h
    The Photographer object generates a snapshot.
    Parameters
    photographer  The Photographer object.
    parameters  An additional key-value map required for snapshot generation.
    subchannel_image  Captures the main channel image if false. Captures the subchannel image if true.
    exif_user_data  The user data to be recorded in JPEG EXIF. If valid, it is stored in Base64 format in the EXIF USER COMMENT (0x9286).
    exif_user_data_length  The user data to be recorded in JPEG EXIF.
    Return Value
    • 0: Success
    • -1: Failure

    The key-value map below consists of optional items. In addition, OSD-related parameters and EXIF-related parameters can be specified.

    Key
    Default
    M
    Description
    jpeg-quality
    100
     
    Specifies the JPEG image quality. The quality value must be within the range of 0 to 100.
    snapshot-use-sw-encoder
    0
     
    Uses the SW JPEG encoder instead of the HW JPEG encoder.

    Note

    photographerSetIspParameters applies only to Raspberry Pi.

    Example#

    This example captures video from the selected camera device, applies OSD, and generates a JPEG file. If the -a option is selected, a Non-Blocking function is used. When applying the Non-Blocking function, snapshots are generated twice at 1-second intervals, specifying different OSD text each time.

    #include "OasisAPI.h"
    #include "OasisLog.h"
    #include "OasisMedia.h"
    #include "OasisUI.h"
    #include "OasisUtil.h"
    #include "OasisDisplay.h"
    
    #include <thread>
    #include <mutex>
    #include <memory>
    #include <condition_variable>
    
    #include <signal.h>
    
    #define DLOG_APP    0x00010000
    
    #undef DLOG_FLAGS
    #define  DLOG_FLAGS (DLOG_FLAGS_DEFAULT|DLOG_APP/**/)
    
    using namespace oasis;
    
    
    static bool continue_capturing = true;
    
    enum {
      kCaptureStateIdle = 0,
      kCaptureStateImageAvailable,
      kCaptureStateImageDataReady,
      kCaptureStateError,
    };
    
    static std::list<int32_t> capture_state_q;
    
    static std::mutex capture_mutex;
    static std::condition_variable capture_cond;
    static std::vector<char> captured_image_data;
    
    void cancel_handler(int signum)
    {
      continue_capturing = false;
      capture_cond.notify_one();
    }
    
    
    class MyPhotographerObserver : public PhotographerObserver
    {
    public:
      MyPhotographerObserver() {}
      virtual ~MyPhotographerObserver() {}
    
      virtual void onCameraSensorMetaData(int32_t camera_id, const CameraSensorMetaData &metadata) {}
      virtual void onIspMetaData(int32_t camera_id, const IspMetaData &metadata) {}
    
      virtual void onCaptureImageAvailable(bool subchannel_image);
      virtual void onImageDataCompleted(const key_value_map_t &parameters, bool subchannel_image, int32_t width, int32_t height, int32_t format, const std::vector<char> &data);
      virtual void onImageDataCompletedWithError(const key_value_map_t &parameters, bool subchannel_image, int32_t error);
    
    };
    
    
    void MyPhotographerObserver::onCaptureImageAvailable(bool subchannel_image)
    {
      fprintf(stdout, ">>> image available\n");
      {
        std::lock_guard<std::mutex> lock(capture_mutex);
        capture_state_q.push_back(kCaptureStateImageAvailable);
      }
      capture_cond.notify_one();
    }
    
    void MyPhotographerObserver::onImageDataCompleted(const key_value_map_t &parameters, bool subchannel_image, int32_t width, int32_t height, int32_t format, const std::vector<char> &data)
    {
      fprintf(stdout, ">>>>> image data completed: %dx%d, format %d, data size %zd\n", width, height, format, data.size());
      {
        std::lock_guard<std::mutex> lock(capture_mutex);
        capture_state_q.push_back(kCaptureStateImageDataReady);
        captured_image_data = data;
      }
      capture_cond.notify_one();
    }
    
    void MyPhotographerObserver::onImageDataCompletedWithError(const key_value_map_t &parameters, bool subchannel_image, int32_t error) 
    {
      fprintf(stdout, ">>>>> image data completed with error: %d\n", error);
      {
        std::lock_guard<std::mutex> lock(capture_mutex);
        capture_state_q.push_back(kCaptureStateError);
      }
      capture_cond.notify_one();
    }
    
    void print_usage(const char *prog_name)
    {
      fprintf(stdout, "USAGE: %s [-a] [-w width] [-h height] [-q quality] [-t wait-timeout in seconds] [-s skip frame count] <camera id> <output-jpeg-file-path>\n", prog_name);
    }
    
    int main(int argc, char* argv[])
    {
      int32_t err, opt;
      int32_t camera_id = 0, width = 0, height = 0, wait = 5, quality = 100, skip = 6;
      char output_path[PATH_MAX];
      bool use_async = false;
    
      while((opt = getopt(argc, argv, "aw:h:q:t:s:")) != -1 ) {
        switch ( opt ) {
        case 'a':
          use_async = true;
          break;
        case 'w':
          if(optarg == nullptr) {
            print_usage(argv[0]);
            return -1;
          }
          width = atoi(optarg);
          break;
        case 'h':
          if(optarg == nullptr) {
            print_usage(argv[0]);
            return -1;
          }
          height = atoi(optarg);
          break;
        case 'q':
          if(optarg == nullptr) {
            print_usage(argv[0]);
            return -1;
          }
          quality = atoi(optarg);
          if(quality > 100) quality = 100;
          else if(quality < 0) quality = 1;
          break;
        case 't':
          if(optarg == nullptr) {
            print_usage(argv[0]);
            return -1;
          }
          wait = atoi(optarg);
          break;
        case 's':
          if(optarg == nullptr) {
            print_usage(argv[0]);
            return -1;
          }
          skip = atoi(optarg);
          break;
        default:
          fprintf(stderr, "error: unknown option '%c'\n", optopt);
          print_usage(argv[0]);
          return -1;
        }
      }
    
      if(argc-optind < 2) {
        fprintf(stderr, "error: invalid or insufficient arguments\n");
        print_usage(argv[0]);
        return -1;
      }
    
      camera_id = atoi(argv[optind]);
      strncpy(output_path, argv[optind+1], sizeof(output_path)-1);
    
      TRACE0("camera %d, size %dx%d, quality %d, wait timeout %d, skip %d frames, save to %s\n", camera_id, width, height, quality, wait, skip, output_path);
    
      signal(SIGINT, cancel_handler);
    
       ////////////////////////////////////////////////////////////////////////////////////////////
      // init
    
      oasis::key_value_map_t parameters;
    
      parameters["offs-disable"] = "1";         
    
      if(oasis::initialize(parameters) < 0) {
        DLOG(DLOG_ERROR, "Oasis init failed\n");
        return -1;
      }
    
      ////////////////////////////////////////////////////////////////////////////////////////////
      // config cameras
      parameters.clear();
    
    
      parameters["source-count"] = "1";
    
      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"] = "1080p";
      parameters["source1-sensor-config"] = "./Resource_tp2863/VIC/0/tp2863_1920x1080_ch0.cfg";
      parameters["source1-autoscene-config"] = "./Resource_tp2863/AutoScene/autoscene_conf.cfg";
      parameters["source1-resource-dir"] = "./Resource_tp2863/";
    
      configCameras(parameters);
    
    
      ////////////////////////////////////////////////////////////////////////////////////////////
      // display setup
      parameters.clear();
    
      parameters["memory-type"] = "ion"; //cma
      parameters["screen-width"] = "480";
      parameters["screen-height"] = "320";
    
      display::setup(parameters);
    
    
      ////////////////////////////////////////////////////////////////////////////////////////////
    
      parameters["camera-id"] = std::to_string(camera_id);
      parameters["width"] = std::to_string(width);
      parameters["height"] = std::to_string(height);
      parameters["quality"] = std::to_string(quality);
      parameters["timeout"] = std::to_string(wait*1000);
      parameters["drop-frame-count"] = std::to_string(skip);
    
      if(use_async) {
    
        std::shared_ptr<MyPhotographerObserver> observer = std::make_shared<MyPhotographerObserver>();
        PhotographerRef photographer = createPhotographer(camera_id, parameters, observer);
    
        if(photographer) {
    
          parameters.clear();
          startPhotographer(photographer);
    
          bool is_capturing = false;
          int32_t image_count = 0;
    
          do {
    
            int32_t state;
    
            {
              std::unique_lock<std::mutex> lock(capture_mutex);
              while(continue_capturing && capture_state_q.empty()) {
                if(wait > 0) {
                  std::cv_status status = capture_cond.wait_for(lock, std::chrono::seconds(wait));
                  if(status == std::cv_status::timeout) {
                    fprintf(stderr, "wait for image available timeout\n");
                    continue_capturing = false;
                    break;
                  }
                } else {
                  capture_cond.wait(lock);
                }
              }
              if(capture_state_q.empty()) {
                continue;
              } else {
                state = capture_state_q.front();
                capture_state_q.pop_front();
              }
            }
    
            auto triggerSnapshot = [&](int32_t image_index) -> int32_t {
    
              key_value_map_t parameters;
    
              time_t tm;
              struct tm tm_t;
              std::string osd_string;
    
              time(&tm);
              localtime_r(&tm, &tm_t);
    
              osd_string = oasis::format("snapshot<%d> %4d/%02d/%02d %02d:%02d:%02d", image_index, 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);
    
              parameters["osd"] = osd_string;
              parameters["osd-font-size"] = "26";
              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"] = "0,0,0";
              parameters["osd-horz-align"] = "left";
              parameters["osd-vert-align"] = "bottom";
              parameters["osd-font-path"] = "/mnt/sd/consola.ttf";
              parameters["osd-use-fixed-size"] = "0";
    
              return photographerGeneratePicture(photographer, parameters, false, nullptr, 0);
            };  
    
            if(state == kCaptureStateImageAvailable) {
              if(is_capturing == false) {
                is_capturing = 0 ==  triggerSnapshot(image_count);
                if(!is_capturing) {
                  fprintf(stderr, "failed to generate picture\n");
                  break;
                } else {
                  image_count++;
                }
              }
            } else if(state == kCaptureStateImageDataReady) {
              if(captured_image_data.empty() == false) {
    
                std::string path = output_path;
                size_t dot_pos = path.find_last_of(".");
                std::string prefix = dot_pos != std::string::npos ? path.substr(0, dot_pos) : path;
                std::string suffix = dot_pos != std::string::npos ? path.substr(dot_pos) : "";
                std::string this_image_path = prefix + "_" + std::to_string(image_count) + suffix;
                FILE *fp = fopen(this_image_path.c_str(), "wb");
                if(fp) {
                  size_t n, len;
                  for(n=0; n<captured_image_data.size(); n += len) {
                    len = fwrite( captured_image_data.data()+n, 1, captured_image_data.size()-n, fp );
                    if(len == 0) break;
                  }
                  fclose(fp);
                  DLOG0(DLOG_INFO, "%s saved\n", this_image_path.c_str());
                }
              }
              is_capturing = false;
    
              if(image_count == 2) {
                break;
              } else {
                //take another picture
                usleep(1000000);
                if(is_capturing == false) {
                  is_capturing = 0 ==  triggerSnapshot(image_count);
                  if(!is_capturing) {
                    fprintf(stderr, "failed to generate picture\n");
                    break;
                  } else {
                    image_count++;
                  }
                }
              }
            } else if(state == kCaptureStateError) {
              is_capturing = false;
              break;
            }
          } while (continue_capturing);
    
          stopPhotographer(photographer);
          destroyPhotographer(photographer);
        }
    
      } else {
    
        time_t tm;
        struct tm tm_t;
        std::string osd_string;
    
        time(&tm);
        localtime_r(&tm, &tm_t);
    
        osd_string = oasis::format("%4d/%02d/%02d %02d:%02d:%02d 12.0V 12H/11.9V", 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);
    
        parameters["osd"] = osd_string;
        parameters["osd-font-size"] = "16";
        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"] = "0,0,0";
        parameters["osd-horz-align"] = "left";
        parameters["osd-vert-align"] = "bottom";
        parameters["osd-font-path"] = "/mnt/sd/consola.ttf";
        parameters["osd-use-fixed-size"] = "0";
    
        err = takePicture(camera_id, parameters, captured_image_data);
    
        if(err == 0) {
          DLOG0(DLOG_INFO, "snapshot jpeg data %d bytes returned\n", captured_image_data.size());
          FILE *fp = fopen(output_path, "wb");
          if(fp) {
            size_t n, len;
            for(n=0; n<captured_image_data.size(); n += len) {
              len = fwrite( captured_image_data.data()+n, 1, captured_image_data.size()-n, fp );
              if(len == 0) break;
            }
            fclose(fp);
            DLOG0(DLOG_INFO, "%s saved\n", output_path);
          }
        } else {
          DLOG0(DLOG_ERROR, "error %d\n", err);
        }
    
      }
    
      oasis::finalize();
    
      return 0;
    }