Setting the file. One moment.
Subchapter 150.14
examples/send-raw-video.mdMarkdown11 KBView on GitHub
Complete working code for sending custom video as a virtual camera.
Official Sample: VSDK_sendRawVideo in videosdk-windows-rawdata-sample (opens in a new tab)
Inject custom video frames into your session. Use cases:
┌─────────────────────────────────────────────────────────────────┐
│ VIDEO INJECTION FLOW │
├─────────────────────────────────────────────────────────────────┤
│ Your Video Source (file, camera, generated) │
│ ↓ │
│ Convert to YUV420 (I420) │
│ ↓ │
│ IZoomVideoSDKVideoSource::onInitialize() │
│ ↓ │
│ IZoomVideoSDKVideoSender::sendVideoFrame() │
│ ↓ │
│ Participants see your custom video │
└─────────────────────────────────────────────────────────────────┘| Property | Value |
|---|---|
| Format | YUV420 (I420) planar |
| Color Space | YUV (not RGB) |
| Supported Resolutions | 90p, 180p, 360p, 720p, 1080p |
| Frame Rate | Up to 30 fps |
#pragma once
#include <windows.h>
#include <thread>
#include <atomic>
#include "zoom_video_sdk_interface.h"
USING_ZOOM_VIDEO_SDK_NAMESPACE
class VideoSource : public IZoomVideoSDKVideoSource {
public:
VideoSource();
~VideoSource();
// IZoomVideoSDKVideoSource interface
void onInitialize(IZoomVideoSDKVideoSender* sender,
IVideoSDKVector<VideoSourceCapability>* support_cap_list,
VideoSourceCapability& suggest_cap) override;
void onPropertyChange(IVideoSDKVector<VideoSourceCapability>* support_cap_list,
VideoSourceCapability suggest_cap) override;
void onStartSend() override;
void onStopSend() override;
void onUninitialized() override;
private:
void SendLoop();
void GenerateTestFrame(char* yBuffer, char* uBuffer, char* vBuffer,
int width, int height, int frameNum);
IZoomVideoSDKVideoSender* m_sender;
std::thread m_sendThread;
std::atomic<bool> m_sending;
int m_width;
int m_height;
int m_fps;
};#include "VideoSource.h"
#include <iostream>
#include <chrono>
VideoSource::VideoSource()
: m_sender(nullptr)
, m_sending(false)
, m_width(1280)
, m_height(720)
, m_fps(30) {
}
VideoSource
void StartVirtualCamera() {
IZoomVideoSDKVideoHelper* videoHelper = sdk->getVideoHelper();
if (!videoHelper) return;
// Create and set video source
VideoSource* videoSource = new VideoSource();
ZoomVideoSDKErrors err = videoHelper->setExternalVideoSource(videoSource);
if (err != ZoomVideoSDKErrors_Success) {
std::cout << "setExternalVideoSource failed: " << err << std::endl;
return;
}
// Start video (this triggers onStartSend)
videoHelper->startVideo();
}
void StopVirtualCamera() {
IZoomVideoSDKVideoHelper* videoHelper = sdk->getVideoHelper();
if (videoHelper) {
videoHelper->stopVideo();
}
}bool LoadYUVFrame(const std::string& filename, int frameIndex,
char* yBuffer, char* uBuffer, char* vBuffer,
int width, int height) {
std::ifstream file(filename, std::ios::binary);
if (!file.is_open()) return false;
size_t ySize = width * height;
size_t uvSize = ySize / 4;
size_t frameSize = ySize + uvSize * 2;
// Seek to frame
file.seekg(frameIndex * frameSize);
// Read YUV planes
file.read(yBuffer, ySize);
file.read(uBuffer, uvSize);
file.read(vBuffer, uvSize);
return file.good();
}void RGBToYUV420(unsigned char* rgb, char* yBuffer, char* uBuffer, char* vBuffer,
int width, int height) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int rgbIndex = (y * width + x) * 3;
int R = rgb[rgbIndex + 2]; // BGR order
int G = rgb[rgbIndex + 1];
int B = rgb[rgbIndex + 0];
// RGB to YUV conversion (BT.601)
int Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
yBuffer[y * width + x] = (char)Y;
// U and V at quarter resolution
if (y % 2 == 0 && x % 2 == 0) {
int uvIndex = (y / 2) * (width / 2) + (x / 2);
int U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
int V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
uBuffer[uvIndex] = (char)U;
vBuffer[uvIndex] = (char)V;
}
}
}
}ZoomVideoSDKErrors sendVideoFrame(
char* frameBuffer, // Y plane or full frame
char* uBuffer, // U plane (can be nullptr for NV12)
char* vBuffer, // V plane (can be nullptr for NV12)
int width, // Frame width
int height, // Frame height
int frameLength, // Y plane size (width * height)
int rotation // 0, 90, 180, 270
);Cause: Not calling startVideo() after setting source
Fix:
videoHelper->setExternalVideoSource(source);
videoHelper->startVideo(); // Required!Cause: Frame generation slower than frame rate
Fix: Optimize frame generation or reduce resolution
Cause: RGB/BGR order mismatch or wrong YUV conversion
Fix: Verify color space conversion formula