# Capture local screenshots (/en/realtime-media/on-premise-recording/build/customize-the-recording/local-screenshot)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

<_PlatformTabsGroup groupMode="structured" canonicalPlatform="linux-cpp" platforms="[&#x22;linux-cpp&#x22;,&#x22;linux-java&#x22;]" showTabs="true">
  <_PlatformPanel platform="linux-cpp">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="linux-cpp" platform="linux-cpp" />

    On-Premise Recording SDK lets you intercept remote video frames during real-time interaction to review live broadcast content and ensure compliance with regulations.

    This article shows you how to use the On-Premise Recording SDK to implement the screenshot feature in your project.

    ## Understand the tech [#understand-the-tech]

    The On-Premise Recording SDK supports capturing screenshots of remote video in both individual and composite recording modes. You can also take screenshots without recording. The supported formats are:

    * H.264/H.265 encoded frame: Returns video frame data in the original encoding format
    * YUV frame: Returns video frame data in YUV format
    * JPG frame: Returns video frame data in JPG format
    * JPG file: Saves the screenshot as a JPG file in the specified directory

    ## Prerequisites [#prerequisites]

    Before using layouts, complete the steps in the [Quickstart](/en/realtime-media/on-premise-recording/quickstart) guide to integrate the SDK and set up basic recording.

    ## Implementation [#implementation]

    To implement the local screenshot function, follow these steps:

    1. Initialize a recorder instance. Call `enableRecorderVideoFrameCapture` to enable or disable the screenshot function.
    2. After you join the channel, use the `IRecorderVideoFrameObserver` interface to receive callbacks for different types of video frames. These callbacks let you access the captured video data.

    The following sample shows how to configure and enable video frame capture:

    ```cpp
    // Create an observer to receive video frames
    std::unique_ptr<RecorderVideoFrameObserver> videoFrameObserver{new RecorderVideoFrameObserver()};
    agora::rtc::RecorderVideoFrameCaptureConfig videoFrameCaptureConfig;
    if(config.frameCaptureConfig.enable){
        // Set the screenshot type
        videoFrameCaptureConfig.videoFrameType = static_cast<agora::rtc::VideoFrameCaptureType>(config.frameCaptureConfig.videoFrameType);
        // JPG frames and JPG files support setting the screenshot interval
        videoFrameCaptureConfig.jpgCaptureIntervalInSec = config.frameCaptureConfig.jpgCaptureInterval;
        // JPG files require setting the save path for JPG files
        videoFrameCaptureConfig.jpgFileStorePath = config.frameCaptureConfig.jpgFileStorePath.c_str();

        // Set the observer
        videoFrameCaptureConfig.observer = videoFrameObserver.get();
        // Call enableRecorderVideoFrameCapture to enable video frame capture
        recorder->enableRecorderVideoFrameCapture(true, videoFrameCaptureConfig);
    }
    ```

    The SDK supports capturing H.264/H.265 encoded frames, YUV format frames, JPG format frames, and JPG files. Refer to the following `RecorderVideoFrameCaptureConfig` settings for each type of video frame:

    * **H.264/H.265 encoded frames**

      ```cpp
      videoFrameCaptureConfig.videoFrameType = agora::rtc::VIDEO_FORMAT_ENCODED_FRAME_TYPE;
      ```

    * **YUV format frame**

      ```cpp
      videoFrameCaptureConfig.videoFrameType = agora::rtc::VIDEO_FORMAT_YUV_FRAME_TYPE;
      ```

    * **JPG format frame**

      ```cpp
      videoFrameCaptureConfig.videoFrameType = agora::rtc::VIDEO_FORMAT_JPG_FRAME_TYPE;
      // Capture a screenshot every 3 seconds
      videoFrameCaptureConfig.jpgCaptureIntervalInSec = 3;
      ```

    * **JPG files**

      ```cpp
      videoFrameCaptureConfig.videoFrameType = agora::rtc::VIDEO_FORMAT_JPG_FILE_TYPE;
      // Save one image every 10 seconds
      videoFrameCaptureConfig.jpgCaptureIntervalInSec = 10;
      // Make sure the directory exists and is writable
      videoFrameCaptureConfig.jpgFileStorePath = "/tmp/screenshots/";
      ```

    ### Get the captured video frames [#get-the-captured-video-frames]

    The `IRecorderVideoFrameObserver` interface provides callbacks for each video frame format. Use these callbacks to access the captured data.

    ```cpp
    class RecorderVideoFrameObserver : public agora::rtc::IRecorderVideoFrameObserver {
    public:
        ~RecorderVideoFrameObserver() {}

        // YUV data callback
        void onYuvFrameCaptured(const char* channelId, agora::user_id_t userId,
                                const agora::media::base::VideoFrame *frame) override {
            // Handle YUV video frame
            printf("Received YUV frame: channel %s, user %u\n", channelId, userId);
        }

        // H.264/H.265, JPG frame data callback
        void onEncodedFrameReceived(const char* channelId, agora::user_id_t userId,
                                    const uint8_t* imageBuffer, size_t length,
                                    agora::rtc::EncodedVideoFrameInfo videoEncodedFrameInfo) override {
            // Handle encoded video frame
            printf("Received encoded frame: channel %s, user %u, data length %zu\n", channelId, userId, length);
        }

        // JPG file save callback
        void onJPGFileSaved(const char* channelId, agora::user_id_t userId,
                            const char* jpgFilePath) override {
            // JPG file saved successfully
            printf("JPG file saved: channel %s, user %u, path %s\n", channelId, userId, jpgFilePath);
        }
    };
    ```

    ### Stop video frame capture [#stop-video-frame-capture]

    To stop video frame capture, call `enableRecorderVideoFrameCapture` again and set the `enable` parameter to `false`:

    ```cpp
    // Stop the screenshot function
    recorder->enableRecorderVideoFrameCapture(false, videoFrameCaptureConfig);
    ```

    ## Reference [#reference]

    This section provides additional details and related considerations.

    ### Development considerations [#development-considerations]

    #### Video subscription settings [#video-subscription-settings]

    When you use the screenshot feature with YUV, JPG frame, or JPG file formats, set `VideoSubscriptionOptions.encodedFrameOnly` to `false` when calling `subscribeVideo` or `subscribeAllVideo`. The default is `false`.

    #### Recording and screenshots are independent [#recording-and-screenshots-are-independent]

    You can take screenshots without recording. The `startRecording` method controls recording and does not affect screenshots.

    ### API reference [#api-reference]

    * [`enableRecorderVideoFrameCapture`](/en/api-reference/api-ref/on-premise-recording#enablerecordervideoframecapture)
    * [`RecorderVideoFrameCaptureConfig`](/en/api-reference/api-ref/on-premise-recording#recordervideoframecaptureconfig)
    * [`IRecorderVideoFrameObserver`](/en/api-reference/api-ref/on-premise-recording#irecordervideoframeobserver)
    * [`VideoFrameCaptureType`](/en/api-reference/api-ref/on-premise-recording#videoframecapturetype)

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="linux-java">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="linux-cpp" platform="linux-java" />

    On-Premise Recording SDK lets you intercept remote video frames during real-time interaction to review live broadcast content and ensure compliance with regulations.

    This article shows you how to use the On-Premise Recording SDK to implement the screenshot feature in your project.

    ## Understand the tech [#understand-the-tech-1]

    The On-Premise Recording SDK supports capturing screenshots of remote video in both individual and composite recording modes. You can also take screenshots without recording. The supported formats are:

    * H.264/H.265 encoded frame: Returns video frame data in the original encoding format
    * YUV frame: Returns video frame data in YUV format
    * JPG frame: Returns video frame data in JPG format
    * JPG file: Saves the screenshot as a JPG file in the specified directory

    ## Prerequisites [#prerequisites-1]

    Before using layouts, complete the steps in the [Quickstart](/en/realtime-media/on-premise-recording/quickstart) guide to integrate the SDK and set up basic recording.

    ## Implementation [#implementation-1]

    To implement the local screenshot function, follow these steps:

    1. Initialize a recorder instance. Call `enableRecorderVideoFrameCapture` to enable or disable the screenshot function.
    2. After you join the channel, use the `IRecorderVideoFrameObserver` interface to receive callbacks for different types of video frames. These callbacks let you access the captured video data.

    The following sample shows how to configure and enable video frame capture:

    ```java
    // Create an observer to receive video frames
    VideoFrameObserver videoFrameObserver = new VideoFrameObserver();
    RecorderVideoFrameCaptureConfig videoFrameCaptureConfig = new RecorderVideoFrameCaptureConfig();

    // Set the screenshot type
    videoFrameCaptureConfig.setVideoFrameType(Constants.VideoFrameCaptureType.VIDEO_FORMAT_JPG_FRAME_TYPE);
    // JPG frames and JPG files support setting a screenshot interval
    videoFrameCaptureConfig.setJpgCaptureIntervalInSec(5);
    // JPG files require specifying the save path for the JPG files
    videoFrameCaptureConfig.setJpgFileStorePath("/path/to/save/jpg/files/");

    // Set the observer
    videoFrameCaptureConfig.setObserver(videoFrameObserver);
    // Call enableRecorderVideoFrameCapture to enable video frame capture
    agoraMediaRtcRecorder.enableRecorderVideoFrameCapture(true, videoFrameCaptureConfig);
    ```

    The SDK supports capturing H.264/H.265 encoded frames, YUV format frames, JPG format frames, and JPG files. Refer to the following `RecorderVideoFrameCaptureConfig` settings for each type of video frame:

    * **H.264/H.265 encoded frames**

      ```java
      videoFrameCaptureConfig.setVideoFrameType(
          Constants.VideoFrameCaptureType.VIDEO_FORMAT_ENCODED_FRAME_TYPE);
      ```

    * **YUV format frame**

      ```java
      videoFrameCaptureConfig.setVideoFrameType(
          Constants.VideoFrameCaptureType.VIDEO_FORMAT_YUV_FRAME_TYPE);
      ```

    * **JPG format frame**

      ```java
      videoFrameCaptureConfig.setVideoFrameType(
          Constants.VideoFrameCaptureType.VIDEO_FORMAT_JPG_FRAME_TYPE);
      // Capture a screenshot every 3 seconds
      videoFrameCaptureConfig.setJpgCaptureIntervalInSec(3);
      ```

    * **JPG files**

      ```java
      videoFrameCaptureConfig.setVideoFrameType(
          Constants.VideoFrameCaptureType.VIDEO_FORMAT_JPG_FILE_TYPE);
      // Save one image every 10 seconds
      videoFrameCaptureConfig.setJpgCaptureIntervalInSec(10);
      // Make sure the directory exists and is writable
      videoFrameCaptureConfig.setJpgFileStorePath("/tmp/screenshots/");
      ```

    ### Get the captured video frames [#get-the-captured-video-frames-1]

    The `IRecorderVideoFrameObserver` interface provides callbacks for each video frame format. Use these callbacks to access the captured data.

    ```java
    public class VideoFrameObserver implements IRecorderVideoFrameObserver {

        // YUV data callback
        @Override
        public void onYuvFrameCaptured(String channelId, String userId, VideoFrame frame) {
            // Handle YUV video frame
            System.out.println("Received YUV frame: channel " + channelId + ", user " + userId);
            // You can get detailed information of the frame
            System.out.println("Frame timestamp: " + frame.getTimeStamp());
        }

        // H.264/H.265, JPG frame data callback
        @Override
        public void onEncodedFrameReceived(String channelId, String userId,
                                         byte[] imageBuffer, EncodedVideoFrameInfo info) {
            // Handle encoded video frame
            System.out.println("Received encoded frame: channel " + channelId + ", user " + userId +
                              ", data length " + imageBuffer.length);

            // You can process the image data here, for example, save it to a file or run content analysis
            // processImageData(imageBuffer);
        }

        // JPG file save callback
        @Override
        public void onJPGFileSaved(String channelId, String userId, String filename) {
            // JPG file saved successfully
            System.out.println("JPG file saved: channel " + channelId + ", user " + userId +
                              ", file path " + filename);
        }
    }
    ```

    ### Stop video frame capture [#stop-video-frame-capture-1]

    To stop video frame capture, call `enableRecorderVideoFrameCapture` again and set the `enable` parameter to `false`:

    ```java
    // Stop the screenshot function
    agoraMediaRtcRecorder.enableRecorderVideoFrameCapture(false, videoFrameCaptureConfig);
    ```

    ## Reference [#reference-1]

    This section provides additional details and related considerations.

    ### Development considerations [#development-considerations-1]

    #### Video subscription settings [#video-subscription-settings-1]

    When you use the screenshot feature with YUV, JPG frame, or JPG file formats, set `VideoSubscriptionOptions.encodedFrameOnly` to `false` when calling `subscribeVideo` or `subscribeAllVideo`. The default is `false`.

    ```java
    VideoSubscriptionOptions options = new VideoSubscriptionOptions();
    options.setEncodedFrameOnly(false);
    options.setType(Constants.VideoStreamType.VIDEO_STREAM_HIGH);
    agoraMediaRtcRecorder.subscribeAllVideo(options);
    ```

    #### Recording and screenshots are independent [#recording-and-screenshots-are-independent-1]

    You can take screenshots without recording. The `startRecording` method controls recording and does not affect screenshots.

    ### API reference [#api-reference-1]

    * [`enableRecorderVideoFrameCapture`](/en/api-reference/api-ref/on-premise-recording#enablerecordervideoframecapture)
    * [`RecorderVideoFrameCaptureConfig`](/en/api-reference/api-ref/on-premise-recording#recordervideoframecaptureconfig)
    * [`IRecorderVideoFrameObserver`](/en/api-reference/api-ref/on-premise-recording#irecordervideoframeobserver)
    * [`VideoFrameCaptureType`](/en/api-reference/api-ref/on-premise-recording#videoframecapturetype)

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>
</_PlatformTabsGroup>
