Navigation

Ventuz Introduction

  • Introduction
  • Getting Started
  • Ventuz Editions
  • Ventuz Products
  • Realtime Rendering
  • Frequently Asked Questions
  • Common Mistakes
  • Deploying a Ventuz Presentation
  • Scene Performance and Tweaks

Quick Guides

  • Quick Guide Index
  • Business Logic
  • 3D Art
  • 2D Art
  • Programming
  • System Engineer

General

  • Index
  • What's New
  • Ventuz System Requirements
  • Communication Protocol Overview
  • Configuration Editor
  • Audio / Video Configuration
  • Machine Configuration
  • Web Configuration Editor and License Manager
  • GPI Configuration for Runtime or Director
  • Supported Formats
  • Supported Hardware
  • Multisampling / Anti-Aliasing
  • Input Subsystem
  • Ventuz Proprietary Files
  • Migrating Content to Ventuz 6
  • Migrating Content to Ventuz 5
  • Summary Shortcuts
  • Terminology
  • Manual Index

Ventuz Designer

  • Designer Indices
Introduction
  • Designer Introduction Index
  • Designer Overview
  • Realtime Rendering
  • Project Browser
  • Designer Interface
  • Designer Options
  • Working with Nodes
  • Hierarchy and Content Editors
  • 2D Workflow
  • 3D Workflow
  • Animation Workflow
  • Best Practices
  • Reading Data in Ventuz
  • Display Images and Movies
  • Scene Performance and Tweaks
  • Deploying a Ventuz Presentation
  • Render to Disk
User Interface
  • Designer User Interface Index
  • Designer Interface
  • Renderer Window
  • Layer Editor
  • Property Editor
  • Property Groups
  • Hierarchy Editor
  • Content Editor
  • Find and Replace
  • Toolbox
  • Animation Editor
  • Shader Editor
  • Text Editor
  • Message View
  • Scene Tree
  • Stage Editor
  • Container Outline
  • Watches Editor
  • Performance Statistics
2D Workflow
  • 2D Workflow Index
  • 2D Workflow
  • Layer Editor
  • Common Layer Properties
  • IPP Effects
  • Color Correction FX
  • Distortion FX
  • Filter FX
  • Hierarchy and Content Editors
  • Display Images and Movies
3D Workflow
  • 3D Workflow Index
  • 3D Workflow
  • Hierarchy and Content Editors
  • Renderer Window
  • Camera Navigation
  • Manipulate Objects with Gizmos
  • Layer Editor
  • Property Editor
  • Hierarchy Editor
  • Working with Nodes
  • Isolated Objects
  • Containers
  • Text Rendering
  • Character Sets
  • Geometry Import
  • Display Images and Movies
  • Particle System
  • Creating Realistic Reflections
  • Unreal Integration
  • Notch Integration
  • E2E Node Overview
Logic Workflow
  • Logic Workflow Index
  • Hierarchy and Content Editors
  • Content Editor
  • Hierarchy Editor
  • Working with Nodes
  • Property Editor
  • Containers
  • Project and Scene Data
  • Reading Data in Ventuz
  • Display Images and Movies
  • Input Subsystem
  • Multitouch
  • TUIO Protocol
  • Open Sound Control
  • Unreal Integration
  • Notch Integration
  • E2E Node Overview
Animation Workflow
  • Animation Workflow Index
  • Animation Workflow
  • Animation Editor
  • Content Editor
  • Hierarchy Editor
  • Property Editor
  • Animation and State Engine
  • Templates
  • Template Engine
  • Unreal Integration
  • Notch Integration
Project Structure
  • Project Structure Index
  • Annotations
  • Projects and Scenes
  • Project Properties
  • Project Maintenance
  • Project and Scene Data
  • Scene Management
  • Scene Statistics
  • Scene Tree
  • Performance Statistics
How Tos
  • Designer How to Index
  • How to Run Ventuz
  • How to Work with Designer
  • Ventuz Designer Drag&Drop Workflow
  • How to work with Shadows
  • How to Build Content for Multiple Screens
  • How to Use Emoijs
  • How to Build a Template
  • How to Use the Color Difference Keyer
  • How To Use the HDR Engine
  • How Create Lens Flares and Bloom
  • How to Create Visuals Loader Node
  • How to Remote Control with a Phone
  • How to use Head Mounted Displays
  • How to work with 3D Reference Layers
  • How to create a Firework Particle System
  • How to use DDS with new Block Compression modes
  • How to use the Substance Integration
  • How To Integrate Unreal
  • How To Integrate Notch
  • How To use the Vertex Integration
  • How To Control and Customize Ventuz
Reference
  • Available Nodes
  • Animation Nodes
  • Material&Color Nodes
  • Data Nodes
  • E2E Nodes
  • Geometry Nodes
  • Interaction Nodes
  • IO Nodes
  • Layers
  • Light Nodes
  • Logic Nodes
  • Render Option Nodes
  • Slides Nodes
  • Sound Nodes
  • Text Nodes
  • Texture Nodes
  • VR Nodes
  • World Nodes
  • Summary Shortcuts
  • Layer Editor Shortcuts
  • Hierarchy Editor Shortcuts
  • Content Editor Shortcuts
  • Animation Editor Shortcuts
  • Director Shortcuts

Ventuz Director

  • Index
  • Introduction
  • Environment
  • Show
  • User Interface
  • Assets
  • Taking Action
  • Property Editor
  • Shot Box
  • Project Data
  • Pages
  • Playlist
  • Timeline
  • Content References
  • Topology
  • Channels
  • Macros
  • Designing Templates
  • Plug-Ins
  • Shortcuts
  • Command Line Options
  • Application Settings
  • Glossary
  • GPI Configuration

Ventuz Runtime & Configuration

  • Runtime Index
  • Configuration Configuration Editor
  • Machine Configuration
  • Video/Audio Configuration
  • Web Configuration Editor and License Manager
  • Render Setup Editor
  • Warping and Soft-Edging Editor
  • Machine Clustering
  • Supported Hardware
  • Director Mode
  • Runtime How Tos Index
  • How to Configure Audio
  • How to Use Live Options
  • How To Play Out On Multiple Screens
  • How To Render on a Machine Cluster
  • How to Use Head Mounted Displays
  • How to Setup Spout with Ventuz
  • How to Use Newtek NDI
  • How to Use a Mixed Frame Rate Cluster
  • How to Use Tracking

How To

Designer
  • Designer How to Index
  • How to Run Ventuz
  • How to Work with Designer
  • Ventuz Designer Drag&Drop Workflow
  • How to work with Shadows
  • How to Build Content for Multiple Screens
  • How to Use Emoijs
  • How to Build a Template
  • How to Use the Color Difference Keyer
  • How To Use the HDR Engine
  • How Create Lens Flares and Bloom
  • How to Create Visuals Loader Node
  • How to Remote Control with a Phone
  • How to use Head Mounted Displays
  • How to work with 3D Reference Layers
  • How to create a Firework Particle System
  • How to use DDS with new Block Compression modes
  • How to use the Substance Integration
  • How To Integrate Unreal
  • How To Integrate Notch
  • How To build and playback Ventuz Content in Vertex
Runtime & Configuration
  • Runtime How Tos Index
  • How to Configure Audio
  • How to Use Live Options
  • How To Play Out On Multiple Screens
  • How To Render on a Machine Cluster
  • How to use Head Mounted Displays
  • How to setup Spout with Ventuz
  • How to use Newtek NDI
  • How to use a Mixed Frame Rate Cluster
  • How to use Tracking
  • How To Integrate Unreal
  • How To Integrate Notch
  • How To build and playback Ventuz Content in Vertex
Director
  • How To Control Multiple Graphics Independently From Each Other
  • How to use the Companion with Director

Ventuz Node Reference

ANIMATION
  • Mover
  • Alternator
  • Simple Control
  • Timeline Control
  • Anmation Rig
  • Keyframe Animation
  • Animation Group
COLOR/MATERIAL
  • Alpha
  • Fog
  • Ground Fog
  • Sky Box
  • Color to RGBA
  • HSLA to Color
  • RGBA to Color
  • Color Transformer
  • HLSL Shader
  • Color
  • Material
  • Color Picker
  • Substance Material
DATA
  • Database
  • Excel
  • JSON
  • RSS Feed
  • Resource Linker
  • Text File
  • XML
E2E
  • E2E Axis
  • E2E Data
  • E2E Control
  • E2E Layer
  • E2E Provider
  • E2E Node Overview
GEOMETRY
  • Rectangle
  • Rounded Rectangle
  • Gradient Rectangle
  • Overlay Rectangle
  • Cube
  • Circle
  • Sphere
  • Cylinder
  • Cone
  • Torus
  • Chart
  • Random Points
  • Mesh Loader
  • Geometry Import (Live)
  • Volume
  • Get Bounding Box
  • Arrow
  • Particle System
  • Path Renderer
  • Geometry Renderer
INTERACTION
  • Interaction Rect
  • Touch Button
  • Touch Excluder
  • Touch Marker
  • Touch Paint
  • Touch Pattern
  • Touch Proxy
  • Touch Ripples
  • Touch Transformations
  • Web Browser
  • Touch Teleport
  • Touch Simulator
INPUT/OUTPUT (I/O)
  • GPI
  • Joystick
  • Keyboard
  • MIDI
  • Mouse
  • Network
  • Open Sound Control
  • Serial
  • Timecode
  • DMX
  • HTTP
  • RamDiskWriter
LAYER
  • 3D Layers
  • 3D Layer Reference
  • 2D Layers
  • PSD Import Layer
  • E2E Layer
  • Others
LIGHT
  • Light Sources
LOGIC
  • Array Processing
  • Convert To Text
  • Cluster Synchronization
  • Counter
  • Date Time
  • Directory
  • Dispatcher
  • Enumeration
  • Expressions
  • Invert
  • Log
  • Loop Breaker
  • Math Effects
  • Matrix Operations
  • Scene Event
  • Script
  • String Operations
  • System ID
  • Text Splitter
  • Timer
  • Toggle
  • URL
  • Value Switch
  • Value Buffer
  • Variables
  • Visual Indexer
RENDER OPTIONS
  • Alpha Blending
  • Color Write
  • Alpha Testing
  • Clip Plane
  • Filter
  • Mask
  • Mirror
  • Effect
  • Render Cube Map
  • Draw Modes
  • Stencil
  • ZTesting
SOUND
  • Audio Clip
  • Sound
  • Volume Control
  • Audio Analysis
SLIDES
  • Slide Manager
  • Slide
  • Slide Port
  • Pivot
TEXT
  • Text Effects
  • Text Layouts
  • Text Rendering
TEXTURE
  • Background
  • Hatch
  • Image
  • Texture
  • SVG Loader
  • Gradient Texture
  • Live Video
  • Movie Stream
  • Movie Frame
  • Movie Clip
  • Texture Loader
  • Snapshot
  • Snapshot Framebuffer
  • Texture Saver
  • Video Source Selector
  • VIO Input
  • Spout Receiver
  • NDI Receiver
  • Substance Loader
  • QR Code
VR/AR
  • Tracked Devices
  • Draw Tracked Devices
WORLD
  • Axis
  • Billboard
  • GetWorld
  • SetWorld
  • Arrange
  • Ticker
  • Layout
  • Group
  • World Z Sort
  • YesNo
  • Switch
  • Spread
  • Filter Pass
  • Set Pass
  • Hierarchy Container
  • Scene Port
  • Content Container
  • Template Port
  • Container Info
  • Camera
  • Paths

Advanced and Development

  • Advanced and Development Index
  • Command Line Options
  • Ventuz IP Ports
  • Ventuz Machine Service
  • TUIO
  • .NET Scripting
  • HLSL Shader Programming
  • Ventuz API and SDK
  • Ventuz Extension API
  • Ventuz VIO API
  • Ventuz File Format (VFF)
  • Ventuz Stream Out API
  • Lens Calibration File for FreeD
  • E2E Node Overview
  • Unreal Integration
  • Notch Integration
Remoting
  • Remoting Index
  • Remoting Overview
  • How To Control and Customize Ventuz
  • Remoting 4
  • Remoting 4 via Websockets
  • Remoting 4 via HTTP
  • Director Remoting
  • Deprecated Remoting
  • Remoting Machine Signature

Misc

  • Presets
« Previous:
» Index «
Next: »

Ventuz Stream Out API

Table of Contents

  1. Connecting to Ventuz
  2. Chunks and the Pipe Header
    1. Chunk header
    2. Pipe header chunk ('VVSP', 0x56565350)
  3. Retrieving video and audio
    1. Frame header chunk ('fhdr', 0x66686472)
    2. Audio and video chunks
      1. Video chunk ('fvid', 0x66766964)
      2. Audio chunk ('faud', 0x66617564)
  4. Sending commands
    1. Request IDR frame command
    2. Touch commands
    3. Key command
    4. Set encode parameters command
  5. C# example code

The Encoded Stream Out outputs provide a simple pipe based streaming protocol to other processes running on the same machine. This way 3rd party applications can process or distribute the video coming out of Ventuz in real time.

Connecting to Ventuz

Ventuz makes the encoded streams available to other processes via a ​named pipe. These processes will need the proper permissions to access the pipe (usually this means running as the same user or at a higher privilege level than the Ventuz runtime).

The pipe's name is "VentuzOutA" for the first output, and B etc. for any additional outputs. Ventuz accepts an arbitrary number of connections to the named pipes, so for example a stream server can choose whether to handle multiple incoming connections itself or to connect to the pipe once per client served.

Although Ventuz allows arbitrarily many connections to each pipe, all connections will share the same output stream; you can't eg. set a different bitrate for each connection.

Chunks and the Pipe Header

Chunk header

All data Ventuz sends through the pipe is organized in chunks. All chunks start with an 8 byte chunk header structure that looks like this:

offset type description
+00 FourCC Chunk type
+04 uint32 Chunk size in bytes

("uint32" means 32 bit unsigned little endian integer; "FourCC" means Four Character Code, ie. a sequence of 4 character bytes)

The chunk header is directly followed by the chunk data with the given size. For compatibility with future versions please note:

  • Unknown chunk types should be ignored, i.e. skipped
  • If the size in the chunk header is bigger than expected, clients should consume as many bytes as expected and skip the rest. This way structures can be appended to without losing backwards compatiblity.
  • If the size in the chunk header is smaller than expected, clients should treat it as error and disconnect from the pipe

As soon as a client connects to the pipe, Ventuz will first send a Pipe Header chunk with information about the audio and video streams.

Pipe header chunk ('VVSP', 0x56565350)

offset type description
+00 uint32 Protocol version
+04 FourCC Video format
+08 uint32 Video width (pixels)
+12 uint32 Video height (pixels)
+16 uint32 Video frame rate numerator
+20 uint32 Video frame rate denominator
+24 FourCC Audio format
+28 uint32 Audio sample rate (Hz)
+32 uint32 Audio channel count

Notes:

  • The current protocol version is 2, please disconnect from the pipe if the version field is anything else than that.
  • Currently only h.264 video is supported, the video format is 'h264' (0x68323634)
  • Audio is currently always signed 16 bit little endian stereo interleaved PCM at 48KHz, the audio format is 'pc16' (0x70633136)

Retrieving video and audio

After sending the pipe header Ventuz will start transmitting video and audio data through the pipe. Every frame begins with a frame header chunk, followed by video and audio frame payload chunks.

Frame header chunk ('fhdr', 0x66686472)

offset type description
+00 uint32 Frame index
+04 uint32 Frame flags

The frame index is a monotonically increasing number.

Currently the following frame flags are defined:

value description
0x00000001 This video frame is an IDR frame

Audio and video chunks

Video chunk ('fvid', 0x66766964)

This chunk contains exactly one frame worth of encoded video. If the IDR frame flag is set in the frame header it's guaranteed that this frame contains everything that's needed to start or restart a video stream, i.e. Sequence and Picture information, and no reference to past frames.

The first frame sent over a newly opened connection will always be an IDR frame so clients don't need to wait out for it.

Audio chunk ('faud', 0x66617564)

The audio chunk contains "one video frame" worth of PCM encoded audio. Which means, the audio chunk corresponds to the exact point and duration in time the video frame is supposed to be displayed. It's therefore guaranteed that audio and video are always in sync with each other.

Even though audio is uncompressed and audio and video always come together, don't rely on audio chunks having a fixed size. When rendering at NTSCish (/1001) frame rates the audio chunk size is going to vary.

Sending commands

While receiving audio and video clients can send commands to Ventuz to set encoding parameters or inject keyboard and touch input. Each command consists of a command byte followed by an optional command payload structure. The following commands are defined:

byte followed by description
0x00 - No operation
0x01 - Request IDR frame
0x10 Touch parameters Begin Touch
0x11 Touch parameters Move Touch
0x12 Touch parameters End Touch
0x13 Touch parameters Cancel Touch
0x20 Key parameters Key Press
0x30 Encode parameters Set encode parameters

Request IDR frame command

This command instructs the encoder inside Ventuz to emit an IDR frame. Due to the asynchronous nature of the encoding process this may take a frame or two; don't assume the frame received right after sending this command will already be an IDR one.

Touch commands

To inject touch input clients can use the four touch commands. All of them require for following payload:

offset type description
+00 uint32 Touch ID
+04 int32 X coordinate (pixels from left side of viewport)
+08 int32 Y coordinate (pixels from upper side of viewport)

Each "touch" is a sequence of one Begin Touch command, followed by zero or more Move Touch commands, and ended with either an End Touch or Cancel Touch command. For this each touch needs to be assigned a unique ID. Clients can eg. either assign IDs incrementally or randomly whenever a new touch is begun or have a "finger number". The important thing is that it's consistent for one touch and there aren't two touches at the same time with the same ID.

Key command

Clients can inject keystrokes (or rather characters) with the Key Press command followed by this structure:

offset type description
+00 uint32 UTF32 codepoint

Control keys that correspond to control characters such as Backspace or Enter will also work.

This command only works with nodes that accept text input, i.e. Text fields and Web browsers. The single key based nodes won't work.

Set encode parameters command

This command sets certain encode parameters without interrupting the video stream. This way eg. a server can dynamically adjust the bitrate to match client or transport constraints. The parameter structure for this command looks like this:

offset type description
+00 uint32 Rate control mode
+04 uint32 Bitrate or QP

There are two values for the rate control mode:

value description
0x00000000 Encode with constant QP (Second field specifies QP (0..51))
0x00000001 Encode with constant bitrate (Second field specifies bitrate in kbits/s)

The encoder will change its behavior as quickly as possible upon receiving this command. Due to the asynchronous nature of the encoding process it may take a few frames unil the new settings are applied.

C# example code

The following source code opens a connection to Ventuz and dumps the video and audio streams as "test.264" and "test.pcm" into the computer's TEMP directory, and lets you send commands to Ventuz by pressing keys. You're free to copy it partially or in total, or to use it as reference for your own implementation.

using System;
using System.IO;
using System.IO.Pipes;
using System.Runtime.InteropServices;

/// <summary>
/// 
/// Copyright (C) Ventuz 2020. All rights reserved.
/// 
/// Example for reading from the Ventuz StreamOut pipe. 
/// Opens the pipe and dumps the audio and video streams into files. 
/// 
/// Changelog
/// 2019-08-29 [TH] Initial public version
/// 
/// </summary>
namespace StreamOutPipeExample
{
    // The data coming from the pipe is organized in chunks. every chunk starts with this, followed by the chunk data
    [StructLayout(LayoutKind.Sequential)]
    public struct ChunkHeader
    {
        public uint fourCC;            // chunk type (four character code)
        public int size;               // size of chunk data
    }

    // Pipe header with general information (VVSP chunk)
    [StructLayout(LayoutKind.Sequential)]
    public struct PipeHeader
    {
        public static readonly int VERSION = 2;

        public uint hdrVersion;         // should be VERSION

        public uint videoCodecFourCC;   // used video codec, currently 'h264' aka h.264
        public uint videoWidth;         // width of image
        public uint videoHeight;        // height of image
        public uint videoFrameRateNum;  // frame rate numerator
        public uint videoFrameRateDen;  // frame rate denominator

        public uint audioCodecFourCC;   // used audio codec, currently 'pc16' aka 16 bit signed little endian PCM
        public uint audioRate;          // audio sample rate, currently fixed at 48000
        public uint audioChannels;      // audio channel count, currently 2
    }

    // Frame header, gets sent every frame, followed by video and then audio data (fhdr chunk)
    [StructLayout(LayoutKind.Sequential)]
    public struct FrameHeader
    {
        [Flags]
        public enum FrameFlags : uint
        {
            IDR_FRAME = 0x01,           // frame is IDR frame (aka key frame / stream restart/sync point)
        }

        public uint frameIndex;         // frame index. If this isn't perfectly contiguous there was a frame drop in Ventuz
        public FrameFlags flags;        // flags, see above
    }

    // Commands to send back to the encoder. 
    enum PipeCommand : byte
    {        
        Nop = 0x00,             // Do nothing
        
        RequestIDRFrame = 0x01, // Request an IDR frame. it may take a couple of frames until the IDR frame arrives due to latency reasons.
        
        TouchBegin = 0x10,      // Start a touch. Must be followed by a TouchPara structure
        TouchMove = 0x11,       // Move a touch. Must be followed by a TouchPara structure        
        TouchEnd = 0x12,        // Release a touch. Must be followed by a TouchPara structure        
        TouchCancel = 0x13,     // Cancal a touch if possible. Must be followed by a TouchPara structure
        
        Key = 0x20,             // Send a keystroke. Must be followed by a KeyPara structure

        SetEncodePara = 0x30,   // Send encoder parameters. Must be followed by an EncodePara structure
    }
    
    // Parameters for Touch* PipeCommands    
    [StructLayout(LayoutKind.Sequential)]
    public struct TouchPara
    {        
        public uint id;   // numerical id. Must be unique per touch (eg. finger # or something incremental)
        public int x;     // x coordinate in pixels from the left side of the viewport
        public int y;     // y coordinate in pixels from the upper side of the viewport
    };

    // Parameters for the Key PipeCommand
    [StructLayout(LayoutKind.Sequential)]
    public struct KeyPara
    {
        public uint Code;   // UTF32 codepoint for pressed key. Control characters like LF and Backspace work.
    };


    // Parameters for the SetEnodePara PipeCommand
    [StructLayout(LayoutKind.Sequential)]
    public struct EncodePara
    {
        public enum RateControlMode : uint
        {
            ConstQP = 0,  // BitrateOrQP is QP (0..51)
            ConstRate = 1, // BitrateOrQP is rate in kBits/s
        }

        public RateControlMode Mode; 
        public uint BitrateOrQP;
    };

    class Program
    {
        // The following helper functions are only meant as a reference.
        // In a full implementation these should be asynchronous or
        // at least have some kind of timeout/error handling.

        /// <summary>
        /// Read a number of bytes from a stream and return as array
        /// </summary>
        public static byte[] ReadBytes(Stream stream, int length)
        {
            var bytes = new byte[length];
            int done = 0;
            while (done < length)
            {
                int read = stream.Read(bytes, done, length-done);
                if (read == 0) throw new IOException("stream ended");
                done += read;
            }
            return bytes;
        }

        /// <summary>
        /// Read a struct from a stream by just blitting the data
        /// </summary>
        public static T ReadStruct<T>(Stream stream, int size = 0)
        {
            var tsize = Marshal.SizeOf(typeof(T));
            if (size <= 0) size = tsize;
            if (size < tsize) throw new ArgumentException("size is too small");

            var bytes = ReadBytes(stream, size);
            GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
            T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
            handle.Free();

            return theStructure;
        }

        /// <summary>
        /// Send a command to the pipe
        /// </summary>
        /// <param name="cmd"></param>
        /// <returns></returns>
        public static void SendCommand(Stream stream, PipeCommand cmd)
        {
            var bytes = new byte[] { (byte)cmd };
            stream.Write(bytes, 0, 1);
        }

        /// <summary>
        /// Send a command to the pipe, with data struct
        /// </summary>
        public static void SendCommand<T>(Stream stream, PipeCommand cmd, T para)
        {
            int size = Marshal.SizeOf(para);
            byte[] arr = new byte[size+1];
            arr[0] = (byte)cmd;

            var h = GCHandle.Alloc(arr, GCHandleType.Pinned);
            Marshal.StructureToPtr(para, h.AddrOfPinnedObject()+1, false);
            h.Free();

            stream.Write(arr, 0, arr.Length);
        }

        /// <summary>
        /// Make uint FourCC from four characters
        /// </summary>
        public static uint FourCC(char a, char b, char c, char d) => ((uint)a << 24) | ((uint)b << 16) | ((uint)c << 8) | ((uint)d);

        /// <summary>
        /// Entry point here
        /// </summary>
        static void Main(string[] args)
        {
            Console.WriteLine("Ventuz video stream pipe receiver example\n");

            // The pipe name is "VentuzOutA" (or B etc for additional outputs), local only.
            // You can connect to the pipe as many times as you wish (eg. once per client you serve),
            // or you can connect once and handle distribution yourself.
            using (var stream = new NamedPipeClientStream("VentuzOutA"))
            {
                Console.WriteLine("Connecting...\n");

                // connect to the pipe
                stream.Connect();

                // try to get first chunk
                var chunk = ReadStruct<ChunkHeader>(stream);
                if (chunk.fourCC != FourCC('V', 'V', 'S', 'P'))
                    throw new Exception("invalid header from pipe");

                // get header
                var header = ReadStruct<PipeHeader>(stream, chunk.size);
                if (header.hdrVersion != PipeHeader.VERSION)
                    throw new Exception("wrong protocol version");

                // check codecs
                if (header.videoCodecFourCC != FourCC('h', '2', '6', '4') || header.audioCodecFourCC != FourCC('p', 'c', '1', '6'))
                    throw new Exception("unsupported video or audio codec");

                Console.WriteLine($"video: {header.videoWidth}x{header.videoHeight} @ {(float)header.videoFrameRateNum / header.videoFrameRateDen}fps");
                Console.WriteLine($"audio: {header.audioChannels}ch @ {header.audioRate}Hz");
                Console.WriteLine("Press ESC to quit.\n");

                // video should always start with a full IDR frame (key frame with decoder reset,
                // contains metadata such as picture and sequence information). Let's check if this is true.
                bool expectIDRFrame = true;
                float bytespersec = 0;

                // let's open some files to dump the streams into. You can open the .264 file with 
                // VLC or Media Player Classic, or mux video and audio using FFMpeg.                 
                FileStream videoFile = null;
                FileStream audioFile = null;
                try
                {
                    var temppath = Path.GetTempPath();
                    videoFile = File.Create(temppath + "test.264");
                    audioFile = File.Create(temppath + "test.pcm");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"ERROR: Can't create output file(s): {ex.Message}\n");
                }
                
                // now let's receive some stuff! Forever!
                bool quit = false;
                while (!quit)
                {
                    while (Console.KeyAvailable)
                    {
                        var rk = Console.ReadKey();
                        var key = rk.Key;

                        // On second thought, quit if esc is pressed.
                        if ( key == ConsoleKey.Escape )
                        {
                            quit = true;
                            break;
                        }
                        else if (key == ConsoleKey.Spacebar)
                        {
                            // If the space bar is pressed, request an IDR frame
                            // (not setting expectIDRFrame here; it might take a frame or two until the IDR frame arrives)
                            SendCommand(stream, PipeCommand.RequestIDRFrame);
                        }
                        else if (key == ConsoleKey.F1)
                        {
                            // simulate a singular touch
                            var para = new TouchPara
                            {
                                id = 12345,
                                x = 100,
                                y = 100,
                            };
                            SendCommand(stream, PipeCommand.TouchBegin, para);
                            SendCommand(stream, PipeCommand.TouchEnd, para);
                        }
                        else if (rk.KeyChar >= '1' && rk.KeyChar <= '9')
                        {
                            // numeric keys: switch encoder bitrate to 1 mbit per key :)
                            SendCommand(stream, PipeCommand.SetEncodePara, new EncodePara
                            {
                                Mode = EncodePara.RateControlMode.ConstRate,
                                BitrateOrQP = ((uint)rk.KeyChar - '0') * 1000,
                            });
                        }
                        else
                        {
                            // forward all other keys to Ventuz
                            SendCommand(stream, PipeCommand.Key, new KeyPara
                            {
                                Code = rk.KeyChar
                            });
                        }

                    }

                    try
                    {
                        // frame header first
                        chunk = ReadStruct<ChunkHeader>(stream);
                        if (chunk.fourCC != FourCC('f', 'h', 'd', 'r'))
                        {
                            // skip unknown chunks
                            var _ = ReadBytes(stream, chunk.size);
                            continue;
                        }

                        var frameheader = ReadStruct<FrameHeader>(stream, chunk.size);
                        if (expectIDRFrame)
                        {
                            if (!frameheader.flags.HasFlag(FrameHeader.FrameFlags.IDR_FRAME))
                                throw new Exception("IDR frame expected");
                            expectIDRFrame = false;
                        }

                        // read video data
                        chunk = ReadStruct<ChunkHeader>(stream);
                        if (chunk.fourCC != FourCC('f', 'v', 'i', 'd'))
                            throw new Exception("video frame expected");
                        byte[] videoFrame = ReadBytes(stream, chunk.size);

                        // read audio data
                        chunk = ReadStruct<ChunkHeader>(stream);
                        if (chunk.fourCC != FourCC('f', 'a', 'u', 'd'))
                            throw new Exception("audio frame expected");
                        byte[] audioFrame = ReadBytes(stream, chunk.size);

                        // calc video bitrate (exponential moving average over packet size times frame rate)
                        bytespersec += 0.1f * ((float)videoFrame.Length * header.videoFrameRateNum / header.videoFrameRateDen - bytespersec);

                        // print stuff and dump streams into files    
                        if (frameheader.flags.HasFlag(FrameHeader.FrameFlags.IDR_FRAME))
                            Console.WriteLine($"Received IDR frame {frameheader.frameIndex}                    ");
                        Console.Write($"got frame {frameheader.frameIndex}, {bytespersec * 8 / 1000.0f}kbits/s       \r");
                        videoFile?.Write(videoFrame, 0, videoFrame.Length);
                        audioFile?.Write(audioFrame, 0, audioFrame.Length);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine($"pipe read failed: {e.Message}");
                        break;
                    }
                }

                Console.WriteLine("good bye.");
                videoFile?.Close();
                audioFile?.Close();
            }

        }
    }
}

See also:
  • Machine Configuration
  • Supported Vendors

« Previous:
» Index «
Next: »
Copyright 2022 Ventuz Technology