# Raw video processing (/en/realtime-media/rtc/build/capture-and-render-video/raw-video-processing/windows)

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

In certain use-cases, it is necessary to process raw video captured through the camera to achieve desired functionality or enhance the user experience. RTC SDK provides the capability to pre-process and post-process the captured video data, allowing you to implement custom playback effects.

      
  
      
  
      
  
      
## Understand the tech

RTC SDK enables you to pre-process the captured video frames before sending the data to the encoder or perform post-processing on the received video frames after sending the data to the decoder.

The following figure shows the video data processing flow in the SDK video module.

**Process raw video**

![image](https://assets-docs.agora.io/images/video-sdk/video-module-data-processing.svg)

* Position (2) corresponds to the `onCaptureVideoFrame` callback.
* Position (3) corresponds to the `onPreEncodeVideoFrame` callback.
* Position (4) corresponds to the`onRenderVideoFrame` callback.

## Prerequisites

Ensure that you have implemented the [SDK quickstart](/en/realtime-media/rtc/get-started-sdk) in your project.

## Implement raw video processing

To implement raw video data functionality in your project, refer to the following steps:

1. Before joining the channel, create an instance of `IVideoFrameObserver` and call `registerVideoFrameObserver` to register the video observer.

   <CalloutContainer type="warning">
     <CalloutDescription>
       When modifying parameters in a `VideoFrame`, ensure that the updated parameters match the actual video frame in the buffer. Failure to do so may result in unexpected rotation or distortion in both the local preview and the remote video.
     </CalloutDescription>
   </CalloutContainer>

```cpp
// Register or unregister the video observer
BOOL CGrayVideoProcFrameObserver::RegisterVideoFrameObserver(
  BOOL bEnable, IVideoFrameObserver *videoFrameObserver) {

  // Create an AutoPtr instance using IMediaEngine as a template for IMediaEngine
  agora::util::AutoPtr<agora::media::IMediaEngine> mediaEngine;
  // Use the queryInterface method through AutoPtr instance to get a pointer to IMediaEngine instance
  // Access the IMediaEngine instance pointer through the arrow operator of AutoPtr instance
  // Call registerVideoFrameObserver through IMediaEngine instance using AutoPtr instance
  mediaEngine.queryInterface(m_rtcEngine, AGORA_IID_MEDIA_ENGINE);
  int nRet = 0;

  agora::base::AParameter apm(*m_rtcEngine);

  if (mediaEngine.get() == NULL) return FALSE;

  if (bEnable) {
    // Register the video frame observer
    nRet = mediaEngine->registerVideoFrameObserver(videoFrameObserver);
  } else {
    // Unregister the video observer
    nRet = mediaEngine->registerVideoFrameObserver(nullptr);
  }

  return nRet == 0 ? TRUE : FALSE;
}
```

2. Obtain video data through the `onCaptureVideoFrame` and `onRenderVideoFrame` callbacks and process the video frames according to your requirements.

   ```cpp
   // Process locally captured raw video data from the camera, perform grayscale processing, and then send it back to the SDK
   bool CGrayVideoProcFrameObserver::onCaptureVideoFrame(VideoFrame &videoFrame) {
     // Calculate the size of the video frame
     int nSize = videoFrame.height * videoFrame.width;

     // Apply grayscale processing to the U and V components of the video frame
     memset(videoFrame.uBuffer, 128, nSize / 4);
     memset(videoFrame.vBuffer, 128, nSize / 4);

     // Return true to indicate successful processing
     return true;
   }

   // Process raw video data received from a remote user
   bool CGrayVideoProcFrameObserver::onRenderVideoFrame(const char *channelId,
                             rtc::uid_t remoteUid,
                             VideoFrame &videoFrame) {
     // Return true to indicate that the received video frame is processed successfully
     return true;
   }

   // Apply an average filter to the locally captured raw video data
   bool CAverageFilterVideoProcFrameObserver::onCaptureVideoFrame(
     VideoFrame &videoFrame) {
     // Static variables to control the step size and direction of the average filter
     static int step = 1;
     static bool flag = true;

     // Update the step size based on the flag
     if (flag) {
       step += 2;
     } else {
       step -= 2;
     }

     // Adjust step size and direction based on certain conditions
     if (step >= 151) {
       flag = false;
       step -= 4;
     } else if (step <= 0) {
       flag = true;
       step += 4;
     }

     // Apply average filtering to the Y, U, and V components of the video frame
     AverageFiltering((unsigned char *)videoFrame.yBuffer, videoFrame.width,
             videoFrame.height, step);
     AverageFiltering((unsigned char *)videoFrame.uBuffer, videoFrame.width / 2,
             videoFrame.height / 2, step);
     AverageFiltering((unsigned char *)videoFrame.vBuffer, videoFrame.width / 2,
             videoFrame.height / 2, step);

     // Return true to indicate successful processing
     return true;
   }

   // Process the locally captured raw video data from screen capture
   bool CGrayVideoProcFrameObserver::onScreenCaptureVideoFrame(
     VideoFrame &videoFrame) {
     // Return true to indicate that the screen-captured video frame is processed successfully
     return true;
   }
   ```

## Reference

This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

### Sample project

Agora provides an open source sample project [OriginalVideo](https://github.com/AgoraIO/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/OriginalVideo) on GitHub. Download it or view the source code for a more detailed example.

### API reference

* [`registerVideoFrameObserver`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_irtcengine.html#api_imediaengine_registervideoframeobserver)
* [`registerVideoEncodedFrameObserver`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_irtcengine.html#api_imediaengine_registervideoencodedframeobserver)
* [`onCaptureVideoFrame`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_ivideoframeobserver.html#callback_ivideoframeobserver_oncapturevideoframe)
* [`onRenderVideoFrame`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_ivideoframeobserver.html#callback_ivideoframeobserver_onrendervideoframe)
* [`getVideoFrameProcessMode`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_ivideoframeobserver.html#callback_ivideoframeobserver_getvideoframeprocessmode)
* [`onEncodedVideoFrameReceived`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_ivideoencodedframeobserver.html#callback_ivideoencodedframeobserver_onencodedvideoframereceived)

    
  
      
  
      
  
      
  
