Compare commits

...

17 Commits

2
.gitmodules vendored

@ -1,4 +1,4 @@
[submodule "kasmweb"] [submodule "kasmweb"]
path = kasmweb path = kasmweb
url = https://github.com/kasmtech/noVNC.git url = https://github.com/kasmtech/noVNC.git
branch = master branch = video

@ -13,7 +13,7 @@ RUN apt-get update && \
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata
RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev
RUN apt-get update && apt-get -y install cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver RUN apt-get update && apt-get -y install cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libx264-dev
# Additions for webp # Additions for webp
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz

@ -13,7 +13,7 @@ RUN apt-get update && \
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata
RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev
RUN apt-get update && apt-get -y install cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver RUN apt-get update && apt-get -y install cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libx264-dev
# Additions for webp # Additions for webp
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz

@ -13,7 +13,7 @@ RUN apt-get update && \
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata
RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev
RUN apt-get update && apt-get -y install cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver RUN apt-get update && apt-get -y install cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libx264-dev
# Additions for webp # Additions for webp
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz

@ -11,7 +11,7 @@ RUN apt-get update && \
RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev
RUN apt-get update && apt-get -y install cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver RUN apt-get update && apt-get -y install cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libx264-dev
# Additions for webp # Additions for webp
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz

@ -13,7 +13,7 @@ RUN apt-get update && \
RUN apt-get update && apt-get install -y --no-install-recommends tzdata RUN apt-get update && apt-get install -y --no-install-recommends tzdata
RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev
RUN apt-get update && apt-get -y install cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver RUN apt-get update && apt-get -y install cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libx264-dev
# Additions for webp # Additions for webp
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz

@ -566,7 +566,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
headers->key3[0] = '\0'; headers->key3[0] = '\0';
if ((strlen(handshake) < 92) || (bcmp(handshake, "GET ", 4) != 0) || if ((strlen(handshake) < 92) || (bcmp(handshake, "GET ", 4) != 0) ||
(!strstr(handshake, "Upgrade: websocket"))) { (!strcasestr(handshake, "Upgrade: websocket"))) {
return 0; return 0;
} }
start = handshake+4; start = handshake+4;
@ -587,7 +587,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
if (start) { if (start) {
start += 10; start += 10;
} else { } else {
start = strstr(handshake, "\r\nSec-WebSocket-Origin: "); start = strcasestr(handshake, "\r\nSec-WebSocket-Origin: ");
if (!start) { return 0; } if (!start) { return 0; }
start += 24; start += 24;
} }
@ -595,7 +595,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
strncpy(headers->origin, start, end-start); strncpy(headers->origin, start, end-start);
headers->origin[end-start] = '\0'; headers->origin[end-start] = '\0';
start = strstr(handshake, "\r\nSec-WebSocket-Version: "); start = strcasestr(handshake, "\r\nSec-WebSocket-Version: ");
if (start) { if (start) {
// HyBi/RFC 6455 // HyBi/RFC 6455
start += 25; start += 25;
@ -605,7 +605,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
ws_ctx->hixie = 0; ws_ctx->hixie = 0;
ws_ctx->hybi = strtol(headers->version, NULL, 10); ws_ctx->hybi = strtol(headers->version, NULL, 10);
start = strstr(handshake, "\r\nSec-WebSocket-Key: "); start = strcasestr(handshake, "\r\nSec-WebSocket-Key: ");
if (!start) { return 0; } if (!start) { return 0; }
start += 21; start += 21;
end = strstr(start, "\r\n"); end = strstr(start, "\r\n");
@ -619,7 +619,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
strncpy(headers->connection, start, end-start); strncpy(headers->connection, start, end-start);
headers->connection[end-start] = '\0'; headers->connection[end-start] = '\0';
start = strstr(handshake, "\r\nSec-WebSocket-Protocol: "); start = strcasestr(handshake, "\r\nSec-WebSocket-Protocol: ");
if (!start) { return 0; } if (!start) { return 0; }
start += 26; start += 26;
end = strstr(start, "\r\n"); end = strstr(start, "\r\n");
@ -637,14 +637,14 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
strncpy(headers->key3, start, 8); strncpy(headers->key3, start, 8);
headers->key3[8] = '\0'; headers->key3[8] = '\0';
start = strstr(handshake, "\r\nSec-WebSocket-Key1: "); start = strcasestr(handshake, "\r\nSec-WebSocket-Key1: ");
if (!start) { return 0; } if (!start) { return 0; }
start += 22; start += 22;
end = strstr(start, "\r\n"); end = strstr(start, "\r\n");
strncpy(headers->key1, start, end-start); strncpy(headers->key1, start, end-start);
headers->key1[end-start] = '\0'; headers->key1[end-start] = '\0';
start = strstr(handshake, "\r\nSec-WebSocket-Key2: "); start = strcasestr(handshake, "\r\nSec-WebSocket-Key2: ");
if (!start) { return 0; } if (!start) { return 0; }
start += 22; start += 22;
end = strstr(start, "\r\n"); end = strstr(start, "\r\n");

@ -58,6 +58,7 @@ set(RFB_SOURCES
TightEncoder.cxx TightEncoder.cxx
TightJPEGEncoder.cxx TightJPEGEncoder.cxx
TightWEBPEncoder.cxx TightWEBPEncoder.cxx
TightX264Encoder.cxx
UpdateTracker.cxx UpdateTracker.cxx
VNCSConnectionST.cxx VNCSConnectionST.cxx
VNCServerST.cxx VNCServerST.cxx
@ -65,6 +66,11 @@ set(RFB_SOURCES
ZRLEDecoder.cxx ZRLEDecoder.cxx
encodings.cxx encodings.cxx
util.cxx util.cxx
mp4.c
mp4_bitbuf.c
mp4_moov.c
mp4_moof.c
nvidia.cxx
xxhash.c) xxhash.c)
if(UNIX) if(UNIX)

@ -50,7 +50,7 @@ namespace rfb {
int w, int h, int w, int h,
const ScreenSet& layout); const ScreenSet& layout);
virtual void setCursor(int width, int height, const Point& hotspot, virtual void setCursor(int width, int height, const Point& hotspot,
const rdr::U8* data) = 0; const rdr::U8* data, const bool resizing = false) = 0;
virtual void setPixelFormat(const PixelFormat& pf); virtual void setPixelFormat(const PixelFormat& pf);
virtual void setName(const char* name); virtual void setName(const char* name);
virtual void fence(rdr::U32 flags, unsigned len, const char data[]); virtual void fence(rdr::U32 flags, unsigned len, const char data[]);

@ -40,6 +40,7 @@
#include <rfb/TightEncoder.h> #include <rfb/TightEncoder.h>
#include <rfb/TightJPEGEncoder.h> #include <rfb/TightJPEGEncoder.h>
#include <rfb/TightWEBPEncoder.h> #include <rfb/TightWEBPEncoder.h>
#include <rfb/TightX264Encoder.h>
using namespace rfb; using namespace rfb;
@ -68,6 +69,7 @@ enum EncoderClass {
encoderTight, encoderTight,
encoderTightJPEG, encoderTightJPEG,
encoderTightWEBP, encoderTightWEBP,
encoderTightX264,
encoderZRLE, encoderZRLE,
encoderClassMax, encoderClassMax,
}; };
@ -110,6 +112,8 @@ static const char *encoderClassName(EncoderClass klass)
return "Tight (JPEG)"; return "Tight (JPEG)";
case encoderTightWEBP: case encoderTightWEBP:
return "Tight (WEBP)"; return "Tight (WEBP)";
case encoderTightX264:
return "Tight (X264)";
case encoderZRLE: case encoderZRLE:
return "ZRLE"; return "ZRLE";
case encoderClassMax: case encoderClassMax:
@ -170,6 +174,7 @@ EncodeManager::EncodeManager(SConnection* conn_, EncCache *encCache_) : conn(con
encoders[encoderTight] = new TightEncoder(conn); encoders[encoderTight] = new TightEncoder(conn);
encoders[encoderTightJPEG] = new TightJPEGEncoder(conn); encoders[encoderTightJPEG] = new TightJPEGEncoder(conn);
encoders[encoderTightWEBP] = new TightWEBPEncoder(conn); encoders[encoderTightWEBP] = new TightWEBPEncoder(conn);
encoders[encoderTightX264] = new TightX264Encoder(conn, encCache, encoderTightX264);
encoders[encoderZRLE] = new ZRLEEncoder(conn); encoders[encoderZRLE] = new ZRLEEncoder(conn);
webpBenchResult = ((TightWEBPEncoder *) encoders[encoderTightWEBP])->benchmark(); webpBenchResult = ((TightWEBPEncoder *) encoders[encoderTightWEBP])->benchmark();
@ -393,6 +398,18 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,
conn->writer()->writeFramebufferUpdateStart(nRects); conn->writer()->writeFramebufferUpdateStart(nRects);
/*
* In extra-low-quality mode, if x264 is enabled, send entire screen frames
*/
if (rfb::Server::x264Bitrate && videoDetected &&
((TightX264Encoder *) encoders[encoderTightX264])->tryInit(pb)) {
std::vector<Rect> rects;
changed.get_rects(&rects);
updateVideoStats(rects, pb);
writeSubRect(pb->getRect(), pb, encoderFullColour, Palette(), std::vector<uint8_t>(),
false);
} else {
writeCopyRects(copied, copyDelta); writeCopyRects(copied, copyDelta);
writeCopyPassRects(copypassed); writeCopyPassRects(copypassed);
@ -407,6 +424,7 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,
&start, true); &start, true);
if (!videoDetected) // In case detection happened between the calls if (!videoDetected) // In case detection happened between the calls
writeRects(cursorRegion, renderedCursor); writeRects(cursorRegion, renderedCursor);
}
updateQualities(); updateQualities();
@ -617,6 +635,8 @@ Encoder *EncodeManager::startRect(const Rect& rect, int type, const bool trackQu
klass = activeEncoders[activeType]; klass = activeEncoders[activeType];
if (isWebp) if (isWebp)
klass = encoderTightWEBP; klass = encoderTightWEBP;
else if (rfb::Server::x264Bitrate && videoDetected) // if x264 enabled
klass = encoderTightX264;
beforeLength = conn->getOutStream()->length(); beforeLength = conn->getOutStream()->length();
@ -656,6 +676,8 @@ void EncodeManager::endRect(const uint8_t isWebp)
klass = activeEncoders[activeType]; klass = activeEncoders[activeType];
if (isWebp) if (isWebp)
klass = encoderTightWEBP; klass = encoderTightWEBP;
else if (rfb::Server::x264Bitrate && videoDetected) // if x264 enabled
klass = encoderTightX264;
stats[klass][activeType].bytes += length; stats[klass][activeType].bytes += length;
} }
@ -861,6 +883,8 @@ void EncodeManager::updateVideoStats(const std::vector<Rect> &rects, const Pixel
uint32_t i; uint32_t i;
if (!rfb::Server::videoTime) { if (!rfb::Server::videoTime) {
if (!videoDetected)
((TightX264Encoder *) encoders[encoderTightX264])->setKeyframe();
videoDetected = true; videoDetected = true;
return; return;
} }
@ -888,6 +912,8 @@ void EncodeManager::updateVideoStats(const std::vector<Rect> &rects, const Pixel
if (area > (unsigned) rfb::Server::videoArea) { if (area > (unsigned) rfb::Server::videoArea) {
// Initiate low-quality video mode // Initiate low-quality video mode
if (!videoDetected)
((TightX264Encoder *) encoders[encoderTightX264])->setKeyframe();
videoDetected = true; videoDetected = true;
videoTimer.start(1000 * rfb::Server::videoOutTime); videoTimer.start(1000 * rfb::Server::videoOutTime);
} }
@ -1022,11 +1048,6 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
webpTookTooLong = false; webpTookTooLong = false;
changed.get_rects(&rects); changed.get_rects(&rects);
// Update stats
if (mainScreen) {
updateVideoStats(rects, pb);
}
if (videoDetected) { if (videoDetected) {
rects.clear(); rects.clear();
rects.push_back(pb->getRect()); rects.push_back(pb->getRect());
@ -1171,6 +1192,11 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
writeSubRect(subrects[i], pb, encoderTypes[i], palettes[i], compresseds[i], isWebp[i]); writeSubRect(subrects[i], pb, encoderTypes[i], palettes[i], compresseds[i], isWebp[i]);
} }
// Update stats
if (mainScreen) {
updateVideoStats(rects, pb);
}
if (scaledpb) if (scaledpb)
delete scaledpb; delete scaledpb;
} }

@ -199,6 +199,10 @@ rfb::IntParameter rfb::Server::videoScaling
("VideoScaling", ("VideoScaling",
"Scaling method to use when in downscaled video mode. 0 = nearest, 1 = bilinear, 2 = prog bilinear", "Scaling method to use when in downscaled video mode. 0 = nearest, 1 = bilinear, 2 = prog bilinear",
2, 0, 2); 2, 0, 2);
rfb::IntParameter rfb::Server::x264Bitrate
("x264Bitrate",
"Enable x264 encoding for full-screen video, in kbps. Default 0 (off)",
0, 0, 50000);
rfb::BoolParameter rfb::Server::printVideoArea rfb::BoolParameter rfb::Server::printVideoArea
("PrintVideoArea", ("PrintVideoArea",
"Print the detected video area % value.", "Print the detected video area % value.",

@ -59,6 +59,7 @@ namespace rfb {
static IntParameter videoOutTime; static IntParameter videoOutTime;
static IntParameter videoArea; static IntParameter videoArea;
static IntParameter videoScaling; static IntParameter videoScaling;
static IntParameter x264Bitrate;
static StringParameter kasmPasswordFile; static StringParameter kasmPasswordFile;
static BoolParameter printVideoArea; static BoolParameter printVideoArea;
static BoolParameter protocol3_3; static BoolParameter protocol3_3;

@ -24,7 +24,8 @@ namespace rfb {
const unsigned int tightJpeg = 0x09; const unsigned int tightJpeg = 0x09;
const unsigned int tightPng = 0x0a; const unsigned int tightPng = 0x0a;
const unsigned int tightWebp = 0x0b; const unsigned int tightWebp = 0x0b;
const unsigned int tightMaxSubencoding = 0x0b; const unsigned int tightX264 = 0x0c;
const unsigned int tightMaxSubencoding = 0x0c;
// Filters to improve compression efficiency // Filters to improve compression efficiency
const unsigned int tightFilterCopy = 0x00; const unsigned int tightFilterCopy = 0x00;

@ -0,0 +1,507 @@
/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
* Copyright 2014 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <rdr/OutStream.h>
#include <rfb/EncCache.h>
#include <rfb/encodings.h>
#include <rfb/LogWriter.h>
#include <rfb/SConnection.h>
#include <rfb/ServerCore.h>
#include <rfb/PixelBuffer.h>
#include <rfb/TightX264Encoder.h>
#include <rfb/TightConstants.h>
#include <webp/encode.h>
#include <x264.h>
#include "nvidia.h"
#include "mp4.h"
#define MAX_FRAMELEN (1024 * 1024)
using namespace rfb;
static LogWriter vlog("x264");
static const PixelFormat pfRGBX(32, 24, false, true, 255, 255, 255, 0, 8, 16);
static const PixelFormat pfBGRX(32, 24, false, true, 255, 255, 255, 16, 8, 0);
bool TightX264Encoder::skip_nvidia = false;
TightX264Encoder::TightX264Encoder(SConnection* conn, EncCache *cache_, uint8_t cacheType_) :
Encoder(conn, encodingTight, (EncoderFlags)(EncoderUseNativePF | EncoderLossy), -1),
keyframe(true), enc(NULL), params(NULL), mux(NULL), muxstate(NULL), framectr(0),
nvidia_init_done(false), using_nvidia(true),
encCache(cache_), cacheType(cacheType_),
framebuf(NULL), framelen(0), bitbuf(NULL), myw(0), myh(0)
{
params = new x264_param_t;
x264_param_default_preset(params, "veryfast", "zerolatency");
params->i_threads = X264_THREADS_AUTO;
params->i_fps_num = params->i_keyint_max = rfb::Server::frameRate;
params->i_fps_den = 1;
params->rc.i_rc_method = X264_RC_ABR;
params->rc.i_bitrate = rfb::Server::x264Bitrate;
params->i_csp = X264_CSP_I420;
params->i_log_level = X264_LOG_WARNING;
params->b_annexb = 0;
framebuf = new uint8_t[MAX_FRAMELEN];
bitbuf = new uint8_t[MAX_FRAMELEN];
mux = new Mp4Context;
memset(mux, 0, sizeof(Mp4Context));
muxstate = new Mp4State;
memset(muxstate, 0, sizeof(Mp4State));
}
TightX264Encoder::~TightX264Encoder()
{
delete params;
delete [] framebuf;
delete [] bitbuf;
delete mux;
delete muxstate;
}
bool TightX264Encoder::isSupported()
{
if (!conn->cp.supportsEncoding(encodingTight))
return false;
// Unconditional support if enabled
return rfb::Server::x264Bitrate != 0;
}
void TightX264Encoder::mp4_write_callback(const void *buffer, size_t size)
{
if (framelen + size > MAX_FRAMELEN)
vlog.error("Tried to write too large a frame, %lu bytes", framelen + size);
memcpy(&framebuf[framelen], buffer, size);
framelen += size;
}
void TightX264Encoder::writeRect(const PixelBuffer* pb, const Palette& palette)
{
const rdr::U8* buffer;
int stride;
rdr::OutStream* os;
if (pb->width() < 320)
return; // Sometimes we get sent an 1x1 frame, or a cursor
uint32_t w, h;
w = pb->width();
h = pb->height();
os = conn->getOutStream();
if (using_nvidia) {
if (w != myw || h != myh) {
if (nvidia_init_done)
nvidia_unload();
nvidia_init_done = false;
}
if (!nvidia_init_done) {
if (nvidia_init(w, h, rfb::Server::x264Bitrate,
rfb::Server::frameRate) != 0) {
vlog.error("nvidia init failed, disabling h264");
rfb::Server::x264Bitrate.setParam(0);
return;
}
nvidia_init_done = true;
myw = w;
myh = h;
}
uint32_t cachelen;
const void *cachedata;
if (encCache->enabled &&
(cachedata = encCache->get(cacheType, framectr, 0, w, h, cachelen))) {
os->writeU8(tightX264 << 4);
writeCompact(cachelen, os);
os->writeBytes(cachedata, cachelen);
framectr++;
return;
}
if (keyframe) {
framectr = 0;
keyframe = false;
free(mux->buf_header.buf);
free(mux->buf_mdat.buf);
free(mux->buf_moof.buf);
memset(mux, 0, sizeof(Mp4Context));
memset(muxstate, 0, sizeof(Mp4State));
}
mux->framerate = rfb::Server::frameRate;
mux->w = w;
mux->h = h;
buffer = pb->getBuffer(pb->getRect(), &stride);
if (!pfBGRX.equal(pb->getPF())) {
vlog.error("unsupported pixel format");
return;
}
// Encode
uint32_t bitlen;
if (nvenc_frame(buffer, framectr++, bitbuf, bitlen) != 0) {
vlog.error("encoding failed");
return;
}
// Need to parse NALs out of the stream
const uint8_t prefix[3] = { 0, 0, 1 };
const uint8_t *nalptr = bitbuf;
int i_nals = 0;
const uint8_t *nalstarts[32] = { NULL };
uint32_t nallens[32] = { 0 };
uint32_t remlen = bitlen;
while (1) {
const uint8_t *next = (uint8_t *) memmem(nalptr, remlen, prefix, 3);
if (!next)
break;
remlen -= (next + 3) - nalptr;
nalptr = nalstarts[i_nals] = next + 3;
i_nals++;
};
// Lens
int i;
for (i = 0; i < i_nals; i++) {
if (i == i_nals - 1) {
nallens[i] = bitbuf + bitlen - nalstarts[i];
} else {
nallens[i] = nalstarts[i + 1] - nalstarts[i] - 3;
}
}
// Mux
framelen = 0;
os->writeU8(tightX264 << 4);
for (i = 0; i < i_nals; i++) {
uint32_t pack_len = nallens[i];
const uint8_t *pack_data = nalstarts[i];
struct NAL nal; nal_parse_header(&nal, pack_data[0]);
switch (nal.unit_type) {
case NalUnitType_SPS: { set_sps(mux, pack_data, pack_len); break; }
case NalUnitType_PPS: { set_pps(mux, pack_data, pack_len); break; }
case NalUnitType_CodedSliceIdr:
case NalUnitType_CodedSliceNonIdr: {
// Write all remaining NALs under the assumption they are the same type.
const uint32_t origlen = pack_len;
pack_len = bitbuf + bitlen - pack_data;
set_slice(mux, pack_data, origlen, pack_len, nal.unit_type);
break;
}
default: break;
}
if (nal.unit_type != NalUnitType_CodedSliceIdr &&
nal.unit_type != NalUnitType_CodedSliceNonIdr)
continue;
enum BufError err;
if (!muxstate->header_sent) {
struct BitBuf header_buf;
err = get_header(mux, &header_buf); chk_err_continue
mp4_write_callback(header_buf.buf, header_buf.offset);
muxstate->sequence_number = 1;
muxstate->base_data_offset = header_buf.offset;
muxstate->base_media_decode_time = 0;
muxstate->header_sent = true;
muxstate->nals_count = 0;
muxstate->default_sample_duration = default_sample_size;
}
err = set_mp4_state(mux, muxstate); chk_err_continue
{
struct BitBuf moof_buf;
err = get_moof(mux, &moof_buf); chk_err_continue
mp4_write_callback(moof_buf.buf, moof_buf.offset);
}
{
struct BitBuf mdat_buf;
err = get_mdat(mux, &mdat_buf); chk_err_continue
mp4_write_callback(mdat_buf.buf, mdat_buf.offset);
}
break;
}
if (encCache->enabled) {
void *tmp = malloc(framelen);
memcpy(tmp, framebuf, framelen);
encCache->add(cacheType, framectr, 0, w, h, framelen, tmp);
}
writeCompact(framelen, os);
os->writeBytes(framebuf, framelen);
} else {
w += w & 1;
h += h & 1;
params->i_width = w;
params->i_height = h;
x264_param_apply_profile(params, "baseline");
uint32_t cachelen;
const void *cachedata;
if (encCache->enabled &&
(cachedata = encCache->get(cacheType, framectr, 0, w, h, cachelen))) {
os->writeU8(tightX264 << 4);
writeCompact(cachelen, os);
os->writeBytes(cachedata, cachelen);
framectr++;
return;
}
if (keyframe) {
framectr = 0;
keyframe = false;
free(mux->buf_header.buf);
free(mux->buf_mdat.buf);
free(mux->buf_moof.buf);
memset(mux, 0, sizeof(Mp4Context));
memset(muxstate, 0, sizeof(Mp4State));
}
mux->framerate = rfb::Server::frameRate;
mux->w = params->i_width;
mux->h = params->i_height;
if (!enc) {
enc = x264_encoder_open(params);
}
buffer = pb->getBuffer(pb->getRect(), &stride);
// Convert it to yuv420 using libwebp's helper functions
WebPPicture pic;
WebPPictureInit(&pic);
pic.width = pb->getRect().width();
pic.height = pb->getRect().height();
bool freebuffer = false;
if (pic.width & 1 || pic.height & 1) {
// Expand to divisible-by-2 for x264
freebuffer = true;
const uint32_t oldw = pic.width;
const uint32_t oldh = pic.height;
pic.width += pic.width & 1;
pic.height += pic.height & 1;
stride = pic.width;
const rdr::U8 *oldbuffer = buffer;
buffer = (const rdr::U8*) calloc(pic.width * pic.height, 4);
uint32_t y;
for (y = 0; y < oldh; y++)
memcpy((void *) &buffer[y * stride * 4], &oldbuffer[y * oldw * 4], oldw * 4);
}
if (pfRGBX.equal(pb->getPF())) {
WebPPictureImportRGBX(&pic, buffer, stride * 4);
} else if (pfBGRX.equal(pb->getPF())) {
WebPPictureImportBGRX(&pic, buffer, stride * 4);
} else {
rdr::U8* tmpbuf = new rdr::U8[pic.width * pic.height * 3];
pb->getPF().rgbFromBuffer(tmpbuf, (const rdr::U8 *) buffer, pic.width, stride, pic.height);
stride = pic.width * 3;
WebPPictureImportRGB(&pic, tmpbuf, stride);
delete [] tmpbuf;
}
if (freebuffer)
free((void *) buffer);
// Wrap
x264_picture_t pic_in, pic_out;
x264_picture_init(&pic_in);
pic_in.img.i_csp = X264_CSP_I420;
pic_in.img.i_plane = 3;
pic_in.img.plane[0] = pic.y;
pic_in.img.plane[1] = pic.u;
pic_in.img.plane[2] = pic.v;
pic_in.img.i_stride[0] = pic.y_stride;
pic_in.img.i_stride[1] = pic_in.img.i_stride[2] = pic.uv_stride;
pic_in.i_pts = framectr++;
// Encode
int i_nals;
x264_nal_t *nals;
const int len = x264_encoder_encode(enc, &nals, &i_nals, &pic_in, &pic_out);
if (len <= 0 || i_nals <= 0)
vlog.info("encoding error");
// Mux
framelen = 0;
os->writeU8(tightX264 << 4);
int i;
for (i = 0; i < i_nals; i++) {
uint32_t pack_len = nals[i].i_payload - 4;
const uint8_t *pack_data = nals[i].p_payload;
pack_data += 4; // Skip size
struct NAL nal; nal_parse_header(&nal, pack_data[0]);
switch (nal.unit_type) {
case NalUnitType_SPS: { set_sps(mux, pack_data, pack_len); break; }
case NalUnitType_PPS: { set_pps(mux, pack_data, pack_len); break; }
case NalUnitType_CodedSliceIdr:
case NalUnitType_CodedSliceNonIdr: {
// Write all remaining NALs under the assumption they are the same type.
const uint32_t origlen = pack_len;
int j;
for (j = i + 1; j < i_nals; j++)
pack_len += nals[j].i_payload;
set_slice(mux, pack_data, origlen, pack_len, nal.unit_type);
break;
}
default: break;
}
if (nal.unit_type != NalUnitType_CodedSliceIdr &&
nal.unit_type != NalUnitType_CodedSliceNonIdr)
continue;
enum BufError err;
if (!muxstate->header_sent) {
struct BitBuf header_buf;
err = get_header(mux, &header_buf); chk_err_continue
mp4_write_callback(header_buf.buf, header_buf.offset);
muxstate->sequence_number = 1;
muxstate->base_data_offset = header_buf.offset;
muxstate->base_media_decode_time = 0;
muxstate->header_sent = true;
muxstate->nals_count = 0;
muxstate->default_sample_duration = default_sample_size;
}
err = set_mp4_state(mux, muxstate); chk_err_continue
{
struct BitBuf moof_buf;
err = get_moof(mux, &moof_buf); chk_err_continue
mp4_write_callback(moof_buf.buf, moof_buf.offset);
}
{
struct BitBuf mdat_buf;
err = get_mdat(mux, &mdat_buf); chk_err_continue
mp4_write_callback(mdat_buf.buf, mdat_buf.offset);
}
break;
}
if (encCache->enabled) {
void *tmp = malloc(framelen);
memcpy(tmp, framebuf, framelen);
encCache->add(cacheType, framectr, 0, w, h, framelen, tmp);
}
writeCompact(framelen, os);
os->writeBytes(framebuf, framelen);
// Cleanup
WebPPictureFree(&pic);
x264_encoder_close(enc);
enc = NULL;
}
}
void TightX264Encoder::writeSolidRect(int width, int height,
const PixelFormat& pf,
const rdr::U8* colour)
{
// FIXME: Add a shortcut in the X264 compressor to handle this case
// without having to use the default fallback which is very slow.
Encoder::writeSolidRect(width, height, pf, colour);
}
void TightX264Encoder::writeCompact(rdr::U32 value, rdr::OutStream* os) const
{
// Copied from TightEncoder as it's overkill to inherit just for this
rdr::U8 b;
b = value & 0x7F;
if (value <= 0x7F) {
os->writeU8(b);
} else {
os->writeU8(b | 0x80);
b = value >> 7 & 0x7F;
if (value <= 0x3FFF) {
os->writeU8(b);
} else {
os->writeU8(b | 0x80);
os->writeU8(value >> 14 & 0xFF);
}
}
}
bool TightX264Encoder::tryInit(const PixelBuffer* pb) {
if (nvidia_init_done)
return true;
uint32_t w, h;
w = pb->width();
h = pb->height();
if (skip_nvidia || nvidia_init(w, h, rfb::Server::x264Bitrate,
rfb::Server::frameRate) != 0) {
if (!skip_nvidia)
vlog.error("nvidia init failed, falling back to x264");
using_nvidia = false;
nvidia_init_done = true;
skip_nvidia = true;
myw = w;
myh = h;
return true;
}
nvidia_init_done = true;
myw = w;
myh = h;
return true;
}

@ -0,0 +1,82 @@
/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander
* Copyright 2014 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RFB_TIGHTX264ENCODER_H__
#define __RFB_TIGHTX264ENCODER_H__
#include <rfb/Encoder.h>
#include <stdint.h>
#include <vector>
struct x264_t;
struct x264_param_t;
struct Mp4Context;
struct Mp4State;
namespace rfb {
class EncCache;
class TightX264Encoder : public Encoder {
public:
TightX264Encoder(SConnection* conn, EncCache *encCache, uint8_t cacheType);
virtual ~TightX264Encoder();
virtual bool isSupported();
virtual void setQualityLevel(int level) {}
virtual void setFineQualityLevel(int quality, int subsampling) {}
virtual void writeRect(const PixelBuffer* pb, const Palette& palette);
virtual void writeSolidRect(int width, int height,
const PixelFormat& pf,
const rdr::U8* colour);
virtual void setKeyframe() { keyframe = true; }
bool tryInit(const PixelBuffer* pb);
protected:
void writeCompact(rdr::U32 value, rdr::OutStream* os) const;
void mp4_write_callback(const void *buffer, size_t size);
protected:
bool keyframe;
x264_t *enc;
x264_param_t *params;
Mp4Context *mux;
Mp4State *muxstate;
unsigned framectr;
bool nvidia_init_done;
bool using_nvidia;
static bool skip_nvidia;
EncCache *encCache;
uint8_t cacheType;
public:
uint8_t *framebuf;
uint32_t framelen;
uint8_t *bitbuf;
uint16_t myw, myh;
};
}
#endif

@ -79,7 +79,7 @@ namespace rfb {
// cursorData argument contains width*height rgba quadruplets with // cursorData argument contains width*height rgba quadruplets with
// non-premultiplied alpha. // non-premultiplied alpha.
virtual void setCursor(int width, int height, const Point& hotspot, virtual void setCursor(int width, int height, const Point& hotspot,
const rdr::U8* cursorData) = 0; const rdr::U8* cursorData, const bool resizing = false) = 0;
// setCursorPos() tells the server the current position of the cursor, and // setCursorPos() tells the server the current position of the cursor, and
// whether the server initiated that change (e.g. through another X11 // whether the server initiated that change (e.g. through another X11

@ -579,7 +579,7 @@ void VNCServerST::add_copied(const Region& dest, const Point& delta)
} }
void VNCServerST::setCursor(int width, int height, const Point& newHotspot, void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
const rdr::U8* data) const rdr::U8* data, const bool resizing)
{ {
delete cursor; delete cursor;
cursor = new Cursor(width, height, newHotspot, data); cursor = new Cursor(width, height, newHotspot, data);
@ -587,6 +587,13 @@ void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
renderedCursorInvalid = true; renderedCursorInvalid = true;
// If an app has an animated cursor on the resized edge, X internals
// will call for it to be rendered. Unlucky for us, the VNC screen
// is currently pointing to freed memory, and a cursor change
// would want to send a screen update. So, don't do that.
if (resizing)
return;
std::list<VNCSConnectionST*>::iterator ci, ci_next; std::list<VNCSConnectionST*>::iterator ci, ci_next;
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) { for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
ci_next = ci; ci_next++; ci_next = ci; ci_next++;

@ -102,7 +102,7 @@ namespace rfb {
virtual void add_changed(const Region &region); virtual void add_changed(const Region &region);
virtual void add_copied(const Region &dest, const Point &delta); virtual void add_copied(const Region &dest, const Point &delta);
virtual void setCursor(int width, int height, const Point& hotspot, virtual void setCursor(int width, int height, const Point& hotspot,
const rdr::U8* data); const rdr::U8* data, const bool resizing = false);
virtual void setCursorPos(const Point& p, bool warped); virtual void setCursorPos(const Point& p, bool warped);
virtual void setLEDState(unsigned state); virtual void setLEDState(unsigned state);

@ -0,0 +1,423 @@
/*
* This copyright notice applies to this header file only:
*
* Copyright (c) 2016
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the software, and to permit persons to whom the
* software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#if !defined(FFNV_DYNLINK_CUDA_H) && !defined(CUDA_VERSION)
#define FFNV_DYNLINK_CUDA_H
#include <stddef.h>
#define CUDA_VERSION 7050
#if defined(_WIN32) || defined(__CYGWIN__)
#define CUDAAPI __stdcall
#else
#define CUDAAPI
#endif
#define CU_CTX_SCHED_BLOCKING_SYNC 4
typedef int CUdevice;
#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) || defined(__LP64__) || defined(__aarch64__)
typedef unsigned long long CUdeviceptr;
#else
typedef unsigned int CUdeviceptr;
#endif
typedef unsigned long long CUtexObject;
typedef struct CUarray_st *CUarray;
typedef struct CUctx_st *CUcontext;
typedef struct CUstream_st *CUstream;
typedef struct CUevent_st *CUevent;
typedef struct CUfunc_st *CUfunction;
typedef struct CUmod_st *CUmodule;
typedef struct CUmipmappedArray_st *CUmipmappedArray;
typedef struct CUgraphicsResource_st *CUgraphicsResource;
typedef struct CUextMemory_st *CUexternalMemory;
typedef struct CUextSemaphore_st *CUexternalSemaphore;
typedef struct CUlinkState_st *CUlinkState;
typedef enum cudaError_enum {
CUDA_SUCCESS = 0,
CUDA_ERROR_NOT_READY = 600
} CUresult;
/**
* Device properties (subset)
*/
typedef enum CUdevice_attribute_enum {
CU_DEVICE_ATTRIBUTE_CLOCK_RATE = 13,
CU_DEVICE_ATTRIBUTE_TEXTURE_ALIGNMENT = 14,
CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT = 16,
CU_DEVICE_ATTRIBUTE_INTEGRATED = 18,
CU_DEVICE_ATTRIBUTE_CAN_MAP_HOST_MEMORY = 19,
CU_DEVICE_ATTRIBUTE_COMPUTE_MODE = 20,
CU_DEVICE_ATTRIBUTE_CONCURRENT_KERNELS = 31,
CU_DEVICE_ATTRIBUTE_PCI_BUS_ID = 33,
CU_DEVICE_ATTRIBUTE_PCI_DEVICE_ID = 34,
CU_DEVICE_ATTRIBUTE_TCC_DRIVER = 35,
CU_DEVICE_ATTRIBUTE_MEMORY_CLOCK_RATE = 36,
CU_DEVICE_ATTRIBUTE_GLOBAL_MEMORY_BUS_WIDTH = 37,
CU_DEVICE_ATTRIBUTE_ASYNC_ENGINE_COUNT = 40,
CU_DEVICE_ATTRIBUTE_UNIFIED_ADDRESSING = 41,
CU_DEVICE_ATTRIBUTE_PCI_DOMAIN_ID = 50,
CU_DEVICE_ATTRIBUTE_TEXTURE_PITCH_ALIGNMENT = 51,
CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR = 75,
CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR = 76,
CU_DEVICE_ATTRIBUTE_MANAGED_MEMORY = 83,
CU_DEVICE_ATTRIBUTE_MULTI_GPU_BOARD = 84,
CU_DEVICE_ATTRIBUTE_MULTI_GPU_BOARD_GROUP_ID = 85,
} CUdevice_attribute;
typedef enum CUarray_format_enum {
CU_AD_FORMAT_UNSIGNED_INT8 = 0x01,
CU_AD_FORMAT_UNSIGNED_INT16 = 0x02,
CU_AD_FORMAT_UNSIGNED_INT32 = 0x03,
CU_AD_FORMAT_SIGNED_INT8 = 0x08,
CU_AD_FORMAT_SIGNED_INT16 = 0x09,
CU_AD_FORMAT_SIGNED_INT32 = 0x0a,
CU_AD_FORMAT_HALF = 0x10,
CU_AD_FORMAT_FLOAT = 0x20
} CUarray_format;
typedef enum CUmemorytype_enum {
CU_MEMORYTYPE_HOST = 1,
CU_MEMORYTYPE_DEVICE = 2,
CU_MEMORYTYPE_ARRAY = 3
} CUmemorytype;
typedef enum CUlimit_enum {
CU_LIMIT_STACK_SIZE = 0,
CU_LIMIT_PRINTF_FIFO_SIZE = 1,
CU_LIMIT_MALLOC_HEAP_SIZE = 2,
CU_LIMIT_DEV_RUNTIME_SYNC_DEPTH = 3,
CU_LIMIT_DEV_RUNTIME_PENDING_LAUNCH_COUNT = 4
} CUlimit;
typedef enum CUresourcetype_enum {
CU_RESOURCE_TYPE_ARRAY = 0x00,
CU_RESOURCE_TYPE_MIPMAPPED_ARRAY = 0x01,
CU_RESOURCE_TYPE_LINEAR = 0x02,
CU_RESOURCE_TYPE_PITCH2D = 0x03
} CUresourcetype;
typedef enum CUaddress_mode_enum {
CU_TR_ADDRESS_MODE_WRAP = 0,
CU_TR_ADDRESS_MODE_CLAMP = 1,
CU_TR_ADDRESS_MODE_MIRROR = 2,
CU_TR_ADDRESS_MODE_BORDER = 3
} CUaddress_mode;
typedef enum CUfilter_mode_enum {
CU_TR_FILTER_MODE_POINT = 0,
CU_TR_FILTER_MODE_LINEAR = 1
} CUfilter_mode;
typedef enum CUgraphicsRegisterFlags_enum {
CU_GRAPHICS_REGISTER_FLAGS_NONE = 0,
CU_GRAPHICS_REGISTER_FLAGS_READ_ONLY = 1,
CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD = 2,
CU_GRAPHICS_REGISTER_FLAGS_SURFACE_LDST = 4,
CU_GRAPHICS_REGISTER_FLAGS_TEXTURE_GATHER = 8
} CUgraphicsRegisterFlags;
typedef enum CUexternalMemoryHandleType_enum {
CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD = 1,
CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32 = 2,
CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT = 3,
CU_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP = 4,
CU_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE = 5,
} CUexternalMemoryHandleType;
typedef enum CUexternalSemaphoreHandleType_enum {
CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD = 1,
CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32 = 2,
CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT = 3,
CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE = 4
} CUexternalSemaphoreHandleType;
typedef enum CUjit_option_enum
{
CU_JIT_MAX_REGISTERS = 0,
CU_JIT_THREADS_PER_BLOCK = 1,
CU_JIT_WALL_TIME = 2,
CU_JIT_INFO_LOG_BUFFER = 3,
CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES = 4,
CU_JIT_ERROR_LOG_BUFFER = 5,
CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES = 6,
CU_JIT_OPTIMIZATION_LEVEL = 7,
CU_JIT_TARGET_FROM_CUCONTEXT = 8,
CU_JIT_TARGET = 9,
CU_JIT_FALLBACK_STRATEGY = 10,
CU_JIT_GENERATE_DEBUG_INFO = 11,
CU_JIT_LOG_VERBOSE = 12,
CU_JIT_GENERATE_LINE_INFO = 13,
CU_JIT_CACHE_MODE = 14,
CU_JIT_NEW_SM3X_OPT = 15,
CU_JIT_FAST_COMPILE = 16,
CU_JIT_GLOBAL_SYMBOL_NAMES = 17,
CU_JIT_GLOBAL_SYMBOL_ADDRESSES = 18,
CU_JIT_GLOBAL_SYMBOL_COUNT = 19,
CU_JIT_NUM_OPTIONS
} CUjit_option;
typedef enum CUjitInputType_enum
{
CU_JIT_INPUT_CUBIN = 0,
CU_JIT_INPUT_PTX = 1,
CU_JIT_INPUT_FATBINARY = 2,
CU_JIT_INPUT_OBJECT = 3,
CU_JIT_INPUT_LIBRARY = 4,
CU_JIT_NUM_INPUT_TYPES
} CUjitInputType;
#ifndef CU_UUID_HAS_BEEN_DEFINED
#define CU_UUID_HAS_BEEN_DEFINED
typedef struct CUuuid_st {
char bytes[16];
} CUuuid;
#endif
typedef struct CUDA_MEMCPY2D_st {
size_t srcXInBytes;
size_t srcY;
CUmemorytype srcMemoryType;
const void *srcHost;
CUdeviceptr srcDevice;
CUarray srcArray;
size_t srcPitch;
size_t dstXInBytes;
size_t dstY;
CUmemorytype dstMemoryType;
void *dstHost;
CUdeviceptr dstDevice;
CUarray dstArray;
size_t dstPitch;
size_t WidthInBytes;
size_t Height;
} CUDA_MEMCPY2D;
typedef struct CUDA_RESOURCE_DESC_st {
CUresourcetype resType;
union {
struct {
CUarray hArray;
} array;
struct {
CUmipmappedArray hMipmappedArray;
} mipmap;
struct {
CUdeviceptr devPtr;
CUarray_format format;
unsigned int numChannels;
size_t sizeInBytes;
} linear;
struct {
CUdeviceptr devPtr;
CUarray_format format;
unsigned int numChannels;
size_t width;
size_t height;
size_t pitchInBytes;
} pitch2D;
struct {
int reserved[32];
} reserved;
} res;
unsigned int flags;
} CUDA_RESOURCE_DESC;
typedef struct CUDA_TEXTURE_DESC_st {
CUaddress_mode addressMode[3];
CUfilter_mode filterMode;
unsigned int flags;
unsigned int maxAnisotropy;
CUfilter_mode mipmapFilterMode;
float mipmapLevelBias;
float minMipmapLevelClamp;
float maxMipmapLevelClamp;
float borderColor[4];
int reserved[12];
} CUDA_TEXTURE_DESC;
/* Unused type */
typedef struct CUDA_RESOURCE_VIEW_DESC_st CUDA_RESOURCE_VIEW_DESC;
typedef unsigned int GLenum;
typedef unsigned int GLuint;
typedef enum CUGLDeviceList_enum {
CU_GL_DEVICE_LIST_ALL = 1,
CU_GL_DEVICE_LIST_CURRENT_FRAME = 2,
CU_GL_DEVICE_LIST_NEXT_FRAME = 3,
} CUGLDeviceList;
typedef struct CUDA_EXTERNAL_MEMORY_HANDLE_DESC_st {
CUexternalMemoryHandleType type;
union {
int fd;
struct {
void *handle;
const void *name;
} win32;
} handle;
unsigned long long size;
unsigned int flags;
unsigned int reserved[16];
} CUDA_EXTERNAL_MEMORY_HANDLE_DESC;
typedef struct CUDA_EXTERNAL_MEMORY_BUFFER_DESC_st {
unsigned long long offset;
unsigned long long size;
unsigned int flags;
unsigned int reserved[16];
} CUDA_EXTERNAL_MEMORY_BUFFER_DESC;
typedef struct CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC_st {
CUexternalSemaphoreHandleType type;
union {
int fd;
struct {
void *handle;
const void *name;
} win32;
} handle;
unsigned int flags;
unsigned int reserved[16];
} CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC;
typedef struct CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS_st {
struct {
struct {
unsigned long long value;
} fence;
unsigned int reserved[16];
} params;
unsigned int flags;
unsigned int reserved[16];
} CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS;
typedef CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS;
typedef struct CUDA_ARRAY3D_DESCRIPTOR_st {
size_t Width;
size_t Height;
size_t Depth;
CUarray_format Format;
unsigned int NumChannels;
unsigned int Flags;
} CUDA_ARRAY3D_DESCRIPTOR;
typedef struct CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC_st {
unsigned long long offset;
CUDA_ARRAY3D_DESCRIPTOR arrayDesc;
unsigned int numLevels;
unsigned int reserved[16];
} CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC;
#define CU_STREAM_NON_BLOCKING 1
#define CU_EVENT_BLOCKING_SYNC 1
#define CU_EVENT_DISABLE_TIMING 2
#define CU_TRSF_READ_AS_INTEGER 1
typedef void CUDAAPI CUstreamCallback(CUstream hStream, CUresult status, void *userdata);
typedef CUresult CUDAAPI tcuInit(unsigned int Flags);
typedef CUresult CUDAAPI tcuDeviceGetCount(int *count);
typedef CUresult CUDAAPI tcuDeviceGet(CUdevice *device, int ordinal);
typedef CUresult CUDAAPI tcuDeviceGetAttribute(int *pi, CUdevice_attribute attrib, CUdevice dev);
typedef CUresult CUDAAPI tcuDeviceGetName(char *name, int len, CUdevice dev);
typedef CUresult CUDAAPI tcuDeviceGetUuid(CUuuid *uuid, CUdevice dev);
typedef CUresult CUDAAPI tcuDeviceComputeCapability(int *major, int *minor, CUdevice dev);
typedef CUresult CUDAAPI tcuCtxCreate_v2(CUcontext *pctx, unsigned int flags, CUdevice dev);
typedef CUresult CUDAAPI tcuCtxSetLimit(CUlimit limit, size_t value);
typedef CUresult CUDAAPI tcuCtxPushCurrent_v2(CUcontext pctx);
typedef CUresult CUDAAPI tcuCtxPopCurrent_v2(CUcontext *pctx);
typedef CUresult CUDAAPI tcuCtxDestroy_v2(CUcontext ctx);
typedef CUresult CUDAAPI tcuMemAlloc_v2(CUdeviceptr *dptr, size_t bytesize);
typedef CUresult CUDAAPI tcuMemAllocPitch_v2(CUdeviceptr *dptr, size_t *pPitch, size_t WidthInBytes, size_t Height, unsigned int ElementSizeBytes);
typedef CUresult CUDAAPI tcuMemsetD8Async(CUdeviceptr dstDevice, unsigned char uc, size_t N, CUstream hStream);
typedef CUresult CUDAAPI tcuMemFree_v2(CUdeviceptr dptr);
typedef CUresult CUDAAPI tcuMemcpy(CUdeviceptr dst, CUdeviceptr src, size_t bytesize);
typedef CUresult CUDAAPI tcuMemcpyAsync(CUdeviceptr dst, CUdeviceptr src, size_t bytesize, CUstream hStream);
typedef CUresult CUDAAPI tcuMemcpy2D_v2(const CUDA_MEMCPY2D *pcopy);
typedef CUresult CUDAAPI tcuMemcpy2DAsync_v2(const CUDA_MEMCPY2D *pcopy, CUstream hStream);
typedef CUresult CUDAAPI tcuGetErrorName(CUresult error, const char** pstr);
typedef CUresult CUDAAPI tcuGetErrorString(CUresult error, const char** pstr);
typedef CUresult CUDAAPI tcuCtxGetDevice(CUdevice *device);
typedef CUresult CUDAAPI tcuDevicePrimaryCtxRetain(CUcontext *pctx, CUdevice dev);
typedef CUresult CUDAAPI tcuDevicePrimaryCtxRelease(CUdevice dev);
typedef CUresult CUDAAPI tcuDevicePrimaryCtxSetFlags(CUdevice dev, unsigned int flags);
typedef CUresult CUDAAPI tcuDevicePrimaryCtxGetState(CUdevice dev, unsigned int *flags, int *active);
typedef CUresult CUDAAPI tcuDevicePrimaryCtxReset(CUdevice dev);
typedef CUresult CUDAAPI tcuStreamCreate(CUstream *phStream, unsigned int flags);
typedef CUresult CUDAAPI tcuStreamQuery(CUstream hStream);
typedef CUresult CUDAAPI tcuStreamSynchronize(CUstream hStream);
typedef CUresult CUDAAPI tcuStreamDestroy_v2(CUstream hStream);
typedef CUresult CUDAAPI tcuStreamAddCallback(CUstream hStream, CUstreamCallback *callback, void *userdata, unsigned int flags);
typedef CUresult CUDAAPI tcuEventCreate(CUevent *phEvent, unsigned int flags);
typedef CUresult CUDAAPI tcuEventDestroy_v2(CUevent hEvent);
typedef CUresult CUDAAPI tcuEventSynchronize(CUevent hEvent);
typedef CUresult CUDAAPI tcuEventQuery(CUevent hEvent);
typedef CUresult CUDAAPI tcuEventRecord(CUevent hEvent, CUstream hStream);
typedef CUresult CUDAAPI tcuLaunchKernel(CUfunction f, unsigned int gridDimX, unsigned int gridDimY, unsigned int gridDimZ, unsigned int blockDimX, unsigned int blockDimY, unsigned int blockDimZ, unsigned int sharedMemBytes, CUstream hStream, void** kernelParams, void** extra);
typedef CUresult CUDAAPI tcuLinkCreate(unsigned int numOptions, CUjit_option* options, void** optionValues, CUlinkState* stateOut);
typedef CUresult CUDAAPI tcuLinkAddData(CUlinkState state, CUjitInputType type, void* data, size_t size, const char* name, unsigned int numOptions, CUjit_option* options, void** optionValues);
typedef CUresult CUDAAPI tcuLinkComplete(CUlinkState state, void** cubinOut, size_t* sizeOut);
typedef CUresult CUDAAPI tcuLinkDestroy(CUlinkState state);
typedef CUresult CUDAAPI tcuModuleLoadData(CUmodule* module, const void* image);
typedef CUresult CUDAAPI tcuModuleUnload(CUmodule hmod);
typedef CUresult CUDAAPI tcuModuleGetFunction(CUfunction* hfunc, CUmodule hmod, const char* name);
typedef CUresult CUDAAPI tcuModuleGetGlobal(CUdeviceptr *dptr, size_t *bytes, CUmodule hmod, const char* name);
typedef CUresult CUDAAPI tcuTexObjectCreate(CUtexObject* pTexObject, const CUDA_RESOURCE_DESC* pResDesc, const CUDA_TEXTURE_DESC* pTexDesc, const CUDA_RESOURCE_VIEW_DESC* pResViewDesc);
typedef CUresult CUDAAPI tcuTexObjectDestroy(CUtexObject texObject);
typedef CUresult CUDAAPI tcuGLGetDevices_v2(unsigned int* pCudaDeviceCount, CUdevice* pCudaDevices, unsigned int cudaDeviceCount, CUGLDeviceList deviceList);
typedef CUresult CUDAAPI tcuGraphicsGLRegisterImage(CUgraphicsResource* pCudaResource, GLuint image, GLenum target, unsigned int Flags);
typedef CUresult CUDAAPI tcuGraphicsUnregisterResource(CUgraphicsResource resource);
typedef CUresult CUDAAPI tcuGraphicsMapResources(unsigned int count, CUgraphicsResource* resources, CUstream hStream);
typedef CUresult CUDAAPI tcuGraphicsUnmapResources(unsigned int count, CUgraphicsResource* resources, CUstream hStream);
typedef CUresult CUDAAPI tcuGraphicsSubResourceGetMappedArray(CUarray* pArray, CUgraphicsResource resource, unsigned int arrayIndex, unsigned int mipLevel);
typedef CUresult CUDAAPI tcuImportExternalMemory(CUexternalMemory* extMem_out, const CUDA_EXTERNAL_MEMORY_HANDLE_DESC* memHandleDesc);
typedef CUresult CUDAAPI tcuDestroyExternalMemory(CUexternalMemory extMem);
typedef CUresult CUDAAPI tcuExternalMemoryGetMappedBuffer(CUdeviceptr* devPtr, CUexternalMemory extMem, const CUDA_EXTERNAL_MEMORY_BUFFER_DESC* bufferDesc);
typedef CUresult CUDAAPI tcuExternalMemoryGetMappedMipmappedArray(CUmipmappedArray* mipmap, CUexternalMemory extMem, const CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC* mipmapDesc);
typedef CUresult CUDAAPI tcuMipmappedArrayGetLevel(CUarray* pLevelArray, CUmipmappedArray hMipmappedArray, unsigned int level);
typedef CUresult CUDAAPI tcuMipmappedArrayDestroy(CUmipmappedArray hMipmappedArray);
typedef CUresult CUDAAPI tcuImportExternalSemaphore(CUexternalSemaphore* extSem_out, const CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC* semHandleDesc);
typedef CUresult CUDAAPI tcuDestroyExternalSemaphore(CUexternalSemaphore extSem);
typedef CUresult CUDAAPI tcuSignalExternalSemaphoresAsync(const CUexternalSemaphore* extSemArray, const CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS* paramsArray, unsigned int numExtSems, CUstream stream);
typedef CUresult CUDAAPI tcuWaitExternalSemaphoresAsync(const CUexternalSemaphore* extSemArray, const CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS* paramsArray, unsigned int numExtSems, CUstream stream);
#endif

@ -0,0 +1,340 @@
/*
* This copyright notice applies to this header file only:
*
* Copyright (c) 2016
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the software, and to permit persons to whom the
* software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef FFNV_CUDA_DYNLINK_LOADER_H
#define FFNV_CUDA_DYNLINK_LOADER_H
#include <stdlib.h>
#include "dynlink_cuda.h"
#include "nvEncodeAPI.h"
#if defined(_WIN32) && (!defined(FFNV_LOAD_FUNC) || !defined(FFNV_SYM_FUNC) || !defined(FFNV_LIB_HANDLE))
# include <windows.h>
#endif
#ifndef FFNV_LIB_HANDLE
# if defined(_WIN32)
# define FFNV_LIB_HANDLE HMODULE
# else
# define FFNV_LIB_HANDLE void*
# endif
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
# define CUDA_LIBNAME "nvcuda.dll"
# define NVCUVID_LIBNAME "nvcuvid.dll"
# if defined(_WIN64) || defined(__CYGWIN64__)
# define NVENC_LIBNAME "nvEncodeAPI64.dll"
# else
# define NVENC_LIBNAME "nvEncodeAPI.dll"
# endif
#else
# define CUDA_LIBNAME "libcuda.so.1"
# define NVCUVID_LIBNAME "libnvcuvid.so.1"
# define NVENC_LIBNAME "libnvidia-encode.so.1"
#endif
#if !defined(FFNV_LOAD_FUNC) || !defined(FFNV_SYM_FUNC)
# ifdef _WIN32
# define FFNV_LOAD_FUNC(path) LoadLibrary(TEXT(path))
# define FFNV_SYM_FUNC(lib, sym) GetProcAddress((lib), (sym))
# define FFNV_FREE_FUNC(lib) FreeLibrary(lib)
# else
# include <dlfcn.h>
# define FFNV_LOAD_FUNC(path) dlopen((path), RTLD_LAZY)
# define FFNV_SYM_FUNC(lib, sym) dlsym((lib), (sym))
# define FFNV_FREE_FUNC(lib) dlclose(lib)
# endif
#endif
#if !defined(FFNV_LOG_FUNC) || !defined(FFNV_DEBUG_LOG_FUNC)
# include <stdio.h>
# define FFNV_LOG_FUNC(logctx, msg, ...) fprintf(stderr, (msg), __VA_ARGS__)
# define FFNV_DEBUG_LOG_FUNC(logctx, msg, ...)
#endif
#define LOAD_LIBRARY(l, path) \
do { \
if (!((l) = FFNV_LOAD_FUNC(path))) { \
FFNV_LOG_FUNC(logctx, "Cannot load %s\n", path); \
ret = -1; \
goto error; \
} \
FFNV_DEBUG_LOG_FUNC(logctx, "Loaded lib: %s\n", path); \
} while (0)
#define LOAD_SYMBOL(fun, tp, symbol) \
do { \
if (!((f->fun) = (tp*)FFNV_SYM_FUNC(f->lib, symbol))) { \
FFNV_LOG_FUNC(logctx, "Cannot load %s\n", symbol); \
ret = -1; \
goto error; \
} \
FFNV_DEBUG_LOG_FUNC(logctx, "Loaded sym: %s\n", symbol); \
} while (0)
#define LOAD_SYMBOL_OPT(fun, tp, symbol) \
do { \
if (!((f->fun) = (tp*)FFNV_SYM_FUNC(f->lib, symbol))) { \
FFNV_DEBUG_LOG_FUNC(logctx, "Cannot load optional %s\n", symbol); \
} else { \
FFNV_DEBUG_LOG_FUNC(logctx, "Loaded sym: %s\n", symbol); \
} \
} while (0)
#define GENERIC_LOAD_FUNC_PREAMBLE(T, n, N) \
T *f; \
int ret; \
\
n##_free_functions(functions); \
\
f = *functions = (T*)calloc(1, sizeof(*f)); \
if (!f) \
return -1; \
\
LOAD_LIBRARY(f->lib, N);
#define GENERIC_LOAD_FUNC_FINALE(n) \
return 0; \
error: \
n##_free_functions(functions); \
return ret;
#define GENERIC_FREE_FUNC() \
if (!functions) \
return; \
if (*functions && (*functions)->lib) \
FFNV_FREE_FUNC((*functions)->lib); \
free(*functions); \
*functions = NULL;
#ifdef FFNV_DYNLINK_CUDA_H
typedef struct CudaFunctions {
tcuInit *cuInit;
tcuDeviceGetCount *cuDeviceGetCount;
tcuDeviceGet *cuDeviceGet;
tcuDeviceGetAttribute *cuDeviceGetAttribute;
tcuDeviceGetName *cuDeviceGetName;
tcuDeviceGetUuid *cuDeviceGetUuid;
tcuDeviceComputeCapability *cuDeviceComputeCapability;
tcuCtxCreate_v2 *cuCtxCreate;
tcuCtxSetLimit *cuCtxSetLimit;
tcuCtxPushCurrent_v2 *cuCtxPushCurrent;
tcuCtxPopCurrent_v2 *cuCtxPopCurrent;
tcuCtxDestroy_v2 *cuCtxDestroy;
tcuMemAlloc_v2 *cuMemAlloc;
tcuMemAllocPitch_v2 *cuMemAllocPitch;
tcuMemsetD8Async *cuMemsetD8Async;
tcuMemFree_v2 *cuMemFree;
tcuMemcpy *cuMemcpy;
tcuMemcpyAsync *cuMemcpyAsync;
tcuMemcpy2D_v2 *cuMemcpy2D;
tcuMemcpy2DAsync_v2 *cuMemcpy2DAsync;
tcuGetErrorName *cuGetErrorName;
tcuGetErrorString *cuGetErrorString;
tcuCtxGetDevice *cuCtxGetDevice;
tcuDevicePrimaryCtxRetain *cuDevicePrimaryCtxRetain;
tcuDevicePrimaryCtxRelease *cuDevicePrimaryCtxRelease;
tcuDevicePrimaryCtxSetFlags *cuDevicePrimaryCtxSetFlags;
tcuDevicePrimaryCtxGetState *cuDevicePrimaryCtxGetState;
tcuDevicePrimaryCtxReset *cuDevicePrimaryCtxReset;
tcuStreamCreate *cuStreamCreate;
tcuStreamQuery *cuStreamQuery;
tcuStreamSynchronize *cuStreamSynchronize;
tcuStreamDestroy_v2 *cuStreamDestroy;
tcuStreamAddCallback *cuStreamAddCallback;
tcuEventCreate *cuEventCreate;
tcuEventDestroy_v2 *cuEventDestroy;
tcuEventSynchronize *cuEventSynchronize;
tcuEventQuery *cuEventQuery;
tcuEventRecord *cuEventRecord;
tcuLaunchKernel *cuLaunchKernel;
tcuLinkCreate *cuLinkCreate;
tcuLinkAddData *cuLinkAddData;
tcuLinkComplete *cuLinkComplete;
tcuLinkDestroy *cuLinkDestroy;
tcuModuleLoadData *cuModuleLoadData;
tcuModuleUnload *cuModuleUnload;
tcuModuleGetFunction *cuModuleGetFunction;
tcuModuleGetGlobal *cuModuleGetGlobal;
tcuTexObjectCreate *cuTexObjectCreate;
tcuTexObjectDestroy *cuTexObjectDestroy;
tcuGLGetDevices_v2 *cuGLGetDevices;
tcuGraphicsGLRegisterImage *cuGraphicsGLRegisterImage;
tcuGraphicsUnregisterResource *cuGraphicsUnregisterResource;
tcuGraphicsMapResources *cuGraphicsMapResources;
tcuGraphicsUnmapResources *cuGraphicsUnmapResources;
tcuGraphicsSubResourceGetMappedArray *cuGraphicsSubResourceGetMappedArray;
tcuImportExternalMemory *cuImportExternalMemory;
tcuDestroyExternalMemory *cuDestroyExternalMemory;
tcuExternalMemoryGetMappedBuffer *cuExternalMemoryGetMappedBuffer;
tcuExternalMemoryGetMappedMipmappedArray *cuExternalMemoryGetMappedMipmappedArray;
tcuMipmappedArrayDestroy *cuMipmappedArrayDestroy;
tcuMipmappedArrayGetLevel *cuMipmappedArrayGetLevel;
tcuImportExternalSemaphore *cuImportExternalSemaphore;
tcuDestroyExternalSemaphore *cuDestroyExternalSemaphore;
tcuSignalExternalSemaphoresAsync *cuSignalExternalSemaphoresAsync;
tcuWaitExternalSemaphoresAsync *cuWaitExternalSemaphoresAsync;
FFNV_LIB_HANDLE lib;
} CudaFunctions;
#else
typedef struct CudaFunctions CudaFunctions;
#endif
typedef NVENCSTATUS NVENCAPI tNvEncodeAPICreateInstance(NV_ENCODE_API_FUNCTION_LIST *functionList);
typedef NVENCSTATUS NVENCAPI tNvEncodeAPIGetMaxSupportedVersion(uint32_t* version);
typedef struct NvencFunctions {
tNvEncodeAPICreateInstance *NvEncodeAPICreateInstance;
tNvEncodeAPIGetMaxSupportedVersion *NvEncodeAPIGetMaxSupportedVersion;
FFNV_LIB_HANDLE lib;
} NvencFunctions;
#ifdef FFNV_DYNLINK_CUDA_H
static inline void cuda_free_functions(CudaFunctions **functions)
{
GENERIC_FREE_FUNC();
}
#endif
static inline void nvenc_free_functions(NvencFunctions **functions)
{
GENERIC_FREE_FUNC();
}
#ifdef FFNV_DYNLINK_CUDA_H
static inline int cuda_load_functions(CudaFunctions **functions)
{
GENERIC_LOAD_FUNC_PREAMBLE(CudaFunctions, cuda, CUDA_LIBNAME);
LOAD_SYMBOL(cuInit, tcuInit, "cuInit");
LOAD_SYMBOL(cuDeviceGetCount, tcuDeviceGetCount, "cuDeviceGetCount");
LOAD_SYMBOL(cuDeviceGet, tcuDeviceGet, "cuDeviceGet");
LOAD_SYMBOL(cuDeviceGetAttribute, tcuDeviceGetAttribute, "cuDeviceGetAttribute");
LOAD_SYMBOL(cuDeviceGetName, tcuDeviceGetName, "cuDeviceGetName");
LOAD_SYMBOL(cuDeviceComputeCapability, tcuDeviceComputeCapability, "cuDeviceComputeCapability");
LOAD_SYMBOL(cuCtxCreate, tcuCtxCreate_v2, "cuCtxCreate_v2");
LOAD_SYMBOL(cuCtxSetLimit, tcuCtxSetLimit, "cuCtxSetLimit");
LOAD_SYMBOL(cuCtxPushCurrent, tcuCtxPushCurrent_v2, "cuCtxPushCurrent_v2");
LOAD_SYMBOL(cuCtxPopCurrent, tcuCtxPopCurrent_v2, "cuCtxPopCurrent_v2");
LOAD_SYMBOL(cuCtxDestroy, tcuCtxDestroy_v2, "cuCtxDestroy_v2");
LOAD_SYMBOL(cuMemAlloc, tcuMemAlloc_v2, "cuMemAlloc_v2");
LOAD_SYMBOL(cuMemAllocPitch, tcuMemAllocPitch_v2, "cuMemAllocPitch_v2");
LOAD_SYMBOL(cuMemsetD8Async, tcuMemsetD8Async, "cuMemsetD8Async");
LOAD_SYMBOL(cuMemFree, tcuMemFree_v2, "cuMemFree_v2");
LOAD_SYMBOL(cuMemcpy, tcuMemcpy, "cuMemcpy");
LOAD_SYMBOL(cuMemcpyAsync, tcuMemcpyAsync, "cuMemcpyAsync");
LOAD_SYMBOL(cuMemcpy2D, tcuMemcpy2D_v2, "cuMemcpy2D_v2");
LOAD_SYMBOL(cuMemcpy2DAsync, tcuMemcpy2DAsync_v2, "cuMemcpy2DAsync_v2");
LOAD_SYMBOL(cuGetErrorName, tcuGetErrorName, "cuGetErrorName");
LOAD_SYMBOL(cuGetErrorString, tcuGetErrorString, "cuGetErrorString");
LOAD_SYMBOL(cuCtxGetDevice, tcuCtxGetDevice, "cuCtxGetDevice");
LOAD_SYMBOL(cuDevicePrimaryCtxRetain, tcuDevicePrimaryCtxRetain, "cuDevicePrimaryCtxRetain");
LOAD_SYMBOL(cuDevicePrimaryCtxRelease, tcuDevicePrimaryCtxRelease, "cuDevicePrimaryCtxRelease");
LOAD_SYMBOL(cuDevicePrimaryCtxSetFlags, tcuDevicePrimaryCtxSetFlags, "cuDevicePrimaryCtxSetFlags");
LOAD_SYMBOL(cuDevicePrimaryCtxGetState, tcuDevicePrimaryCtxGetState, "cuDevicePrimaryCtxGetState");
LOAD_SYMBOL(cuDevicePrimaryCtxReset, tcuDevicePrimaryCtxReset, "cuDevicePrimaryCtxReset");
LOAD_SYMBOL(cuStreamCreate, tcuStreamCreate, "cuStreamCreate");
LOAD_SYMBOL(cuStreamQuery, tcuStreamQuery, "cuStreamQuery");
LOAD_SYMBOL(cuStreamSynchronize, tcuStreamSynchronize, "cuStreamSynchronize");
LOAD_SYMBOL(cuStreamDestroy, tcuStreamDestroy_v2, "cuStreamDestroy_v2");
LOAD_SYMBOL(cuStreamAddCallback, tcuStreamAddCallback, "cuStreamAddCallback");
LOAD_SYMBOL(cuEventCreate, tcuEventCreate, "cuEventCreate");
LOAD_SYMBOL(cuEventDestroy, tcuEventDestroy_v2, "cuEventDestroy_v2");
LOAD_SYMBOL(cuEventSynchronize, tcuEventSynchronize, "cuEventSynchronize");
LOAD_SYMBOL(cuEventQuery, tcuEventQuery, "cuEventQuery");
LOAD_SYMBOL(cuEventRecord, tcuEventRecord, "cuEventRecord");
LOAD_SYMBOL(cuLaunchKernel, tcuLaunchKernel, "cuLaunchKernel");
LOAD_SYMBOL(cuLinkCreate, tcuLinkCreate, "cuLinkCreate");
LOAD_SYMBOL(cuLinkAddData, tcuLinkAddData, "cuLinkAddData");
LOAD_SYMBOL(cuLinkComplete, tcuLinkComplete, "cuLinkComplete");
LOAD_SYMBOL(cuLinkDestroy, tcuLinkDestroy, "cuLinkDestroy");
LOAD_SYMBOL(cuModuleLoadData, tcuModuleLoadData, "cuModuleLoadData");
LOAD_SYMBOL(cuModuleUnload, tcuModuleUnload, "cuModuleUnload");
LOAD_SYMBOL(cuModuleGetFunction, tcuModuleGetFunction, "cuModuleGetFunction");
LOAD_SYMBOL(cuModuleGetGlobal, tcuModuleGetGlobal, "cuModuleGetGlobal");
LOAD_SYMBOL(cuTexObjectCreate, tcuTexObjectCreate, "cuTexObjectCreate");
LOAD_SYMBOL(cuTexObjectDestroy, tcuTexObjectDestroy, "cuTexObjectDestroy");
LOAD_SYMBOL(cuGLGetDevices, tcuGLGetDevices_v2, "cuGLGetDevices_v2");
LOAD_SYMBOL(cuGraphicsGLRegisterImage, tcuGraphicsGLRegisterImage, "cuGraphicsGLRegisterImage");
LOAD_SYMBOL(cuGraphicsUnregisterResource, tcuGraphicsUnregisterResource, "cuGraphicsUnregisterResource");
LOAD_SYMBOL(cuGraphicsMapResources, tcuGraphicsMapResources, "cuGraphicsMapResources");
LOAD_SYMBOL(cuGraphicsUnmapResources, tcuGraphicsUnmapResources, "cuGraphicsUnmapResources");
LOAD_SYMBOL(cuGraphicsSubResourceGetMappedArray, tcuGraphicsSubResourceGetMappedArray, "cuGraphicsSubResourceGetMappedArray");
LOAD_SYMBOL_OPT(cuDeviceGetUuid, tcuDeviceGetUuid, "cuDeviceGetUuid");
LOAD_SYMBOL_OPT(cuImportExternalMemory, tcuImportExternalMemory, "cuImportExternalMemory");
LOAD_SYMBOL_OPT(cuDestroyExternalMemory, tcuDestroyExternalMemory, "cuDestroyExternalMemory");
LOAD_SYMBOL_OPT(cuExternalMemoryGetMappedBuffer, tcuExternalMemoryGetMappedBuffer, "cuExternalMemoryGetMappedBuffer");
LOAD_SYMBOL_OPT(cuExternalMemoryGetMappedMipmappedArray, tcuExternalMemoryGetMappedMipmappedArray, "cuExternalMemoryGetMappedMipmappedArray");
LOAD_SYMBOL_OPT(cuMipmappedArrayGetLevel, tcuMipmappedArrayGetLevel, "cuMipmappedArrayGetLevel");
LOAD_SYMBOL_OPT(cuMipmappedArrayDestroy, tcuMipmappedArrayDestroy, "cuMipmappedArrayDestroy");
LOAD_SYMBOL_OPT(cuImportExternalSemaphore, tcuImportExternalSemaphore, "cuImportExternalSemaphore");
LOAD_SYMBOL_OPT(cuDestroyExternalSemaphore, tcuDestroyExternalSemaphore, "cuDestroyExternalSemaphore");
LOAD_SYMBOL_OPT(cuSignalExternalSemaphoresAsync, tcuSignalExternalSemaphoresAsync, "cuSignalExternalSemaphoresAsync");
LOAD_SYMBOL_OPT(cuWaitExternalSemaphoresAsync, tcuWaitExternalSemaphoresAsync, "cuWaitExternalSemaphoresAsync");
GENERIC_LOAD_FUNC_FINALE(cuda);
}
#endif
static inline int nvenc_load_functions(NvencFunctions **functions)
{
GENERIC_LOAD_FUNC_PREAMBLE(NvencFunctions, nvenc, NVENC_LIBNAME);
LOAD_SYMBOL(NvEncodeAPICreateInstance, tNvEncodeAPICreateInstance, "NvEncodeAPICreateInstance");
LOAD_SYMBOL(NvEncodeAPIGetMaxSupportedVersion, tNvEncodeAPIGetMaxSupportedVersion, "NvEncodeAPIGetMaxSupportedVersion");
GENERIC_LOAD_FUNC_FINALE(nvenc);
}
#undef GENERIC_LOAD_FUNC_PREAMBLE
#undef LOAD_LIBRARY
#undef LOAD_SYMBOL
#undef GENERIC_LOAD_FUNC_FINALE
#undef GENERIC_FREE_FUNC
#undef CUDA_LIBNAME
#undef NVCUVID_LIBNAME
#undef NVENC_LIBNAME
#endif

@ -0,0 +1,98 @@
#include "mp4.h"
#include <string.h>
uint32_t default_sample_size = 40000;
enum BufError create_header();
void set_sps(struct Mp4Context *ctx, const uint8_t* nal_data, const uint32_t nal_len) {
memcpy(ctx->buf_sps, nal_data, nal_len);
ctx->buf_sps_len = nal_len;
create_header(ctx);
}
void set_pps(struct Mp4Context *ctx, const uint8_t* nal_data, const uint32_t nal_len) {
memcpy(ctx->buf_pps, nal_data, nal_len);
ctx->buf_pps_len = nal_len;
create_header(ctx);
}
enum BufError create_header(struct Mp4Context *ctx) {
if (ctx->buf_header.offset > 0) return BUF_OK;
if (ctx->buf_sps_len == 0) return BUF_OK;
if (ctx->buf_pps_len == 0) return BUF_OK;
struct MoovInfo moov_info;
memset(&moov_info, 0, sizeof(struct MoovInfo));
moov_info.width = ctx->w;
moov_info.height = ctx->h;
moov_info.horizontal_resolution = 0x00480000; // 72 dpi
moov_info.vertical_resolution = 0x00480000; // 72 dpi
moov_info.creation_time = 0;
moov_info.timescale = default_sample_size * ctx->framerate;
moov_info.sps = (uint8_t *) ctx->buf_sps;
moov_info.sps_length = ctx->buf_sps_len;
moov_info.pps = (uint8_t *) ctx->buf_pps;
moov_info.pps_length = ctx->buf_pps_len;
ctx->buf_header.offset = 0;
enum BufError err = write_header(&ctx->buf_header, &moov_info); chk_err
return BUF_OK;
}
enum BufError get_header(struct Mp4Context *ctx, struct BitBuf *ptr) {
ptr->buf = ctx->buf_header.buf;
ptr->size = ctx->buf_header.size;
ptr->offset = ctx->buf_header.offset;
return BUF_OK;
}
enum BufError set_slice(struct Mp4Context *ctx, const uint8_t* nal_data, const uint32_t origlen, const uint32_t nal_len, const enum NalUnitType unit_type) {
enum BufError err;
const uint32_t samples_info_len = 1;
struct SampleInfo samples_info[1];
memset(&samples_info[0], 0, sizeof(struct SampleInfo));
samples_info[0].size = nal_len + 4; // add size of sample
samples_info[0].composition_offset = default_sample_size;
samples_info[0].decode_time = default_sample_size;
samples_info[0].duration = default_sample_size;
samples_info[0].flags = unit_type == NalUnitType_CodedSliceIdr ? 0 : 65536;
ctx->buf_moof.offset = 0;
err = write_moof(&ctx->buf_moof, 0, 0, 0, default_sample_size, samples_info, samples_info_len); chk_err
ctx->buf_mdat.offset = 0;
// printf("nal_data %d\n", nal_data);
// printf(" slice: "); for (int i = 0; i < 32; ++i) printf(" 0x%02hhX", nal_data[i]); printf("\n");
err = write_mdat(&ctx->buf_mdat, nal_data, origlen, nal_len); chk_err
return BUF_OK;
}
enum BufError set_mp4_state(struct Mp4Context *ctx, struct Mp4State *state) {
enum BufError err = BUF_OK;
if (pos_sequence_number > 0) err = put_u32_be_to_offset(&ctx->buf_moof, pos_sequence_number, state->sequence_number); chk_err
if (pos_base_data_offset > 0) err = put_u64_be_to_offset(&ctx->buf_moof, pos_base_data_offset, state->base_data_offset); chk_err
if (pos_base_media_decode_time > 0) err = put_u64_be_to_offset(&ctx->buf_moof, pos_base_media_decode_time, state->base_media_decode_time); chk_err
state->sequence_number++;
state->base_data_offset += ctx->buf_moof.offset + ctx->buf_mdat.offset;
state->base_media_decode_time += state->default_sample_duration;
return BUF_OK;
}
enum BufError get_moof(struct Mp4Context *ctx, struct BitBuf *ptr) {
ptr->buf = ctx->buf_moof.buf;
ptr->size = ctx->buf_moof.size;
ptr->offset = ctx->buf_moof.offset;
return BUF_OK;
}
enum BufError get_mdat(struct Mp4Context *ctx, struct BitBuf *ptr) {
ptr->buf = ctx->buf_mdat.buf;
ptr->size = ctx->buf_mdat.size;
ptr->offset = ctx->buf_mdat.offset;
// int o = 4+4;
// printf(" get_mdat: "); for (int i = 0; i < 32; ++i) printf(" 0x%02hhX", ptr->buf[o+i]); printf("\n");
return BUF_OK;
}

@ -0,0 +1,197 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#define chk_err if (err != BUF_OK) { printf("Error buf: %s %s(...) %s:%d\n", buf_error_to_str(err), __func__, __FILE__, __LINE__); return err; }
#define chk_err_continue if (err != BUF_OK) { printf("Error buf: %s %s(...) %s:%d\n", buf_error_to_str(err), __func__, __FILE__, __LINE__); continue; }
enum BufError {
BUF_OK = 0,
BUF_ENDOFBUF_ERROR,
BUF_MALLOC_ERROR,
BUF_INCORRECT
};
char* buf_error_to_str(const enum BufError err);
struct BitBuf {
char *buf;
uint32_t size;
uint32_t offset;
};
enum BufError put_skip(struct BitBuf *ptr, const uint32_t count);
enum BufError put_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint8_t* data, const uint32_t size);
enum BufError put(struct BitBuf *ptr, const uint8_t* data, const uint32_t size);
enum BufError put_u8_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint8_t val);
enum BufError put_u8(struct BitBuf *ptr, uint8_t val);
enum BufError put_u16_be_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint16_t val);
enum BufError put_u16_be(struct BitBuf *ptr, const uint16_t val);
enum BufError put_u16_le_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint16_t val);
enum BufError put_u16_le(struct BitBuf *ptr, const uint16_t val);
enum BufError put_u32_be_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint32_t val);
enum BufError put_u32_be(struct BitBuf *ptr, const uint32_t val);
enum BufError put_i32_be(struct BitBuf *ptr, const int32_t val);
enum BufError put_u64_be_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint64_t val);
enum BufError put_u64_be(struct BitBuf *ptr, const uint64_t val);
enum BufError put_u32_le_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint32_t val);
enum BufError put_u32_le(struct BitBuf *ptr, const uint32_t val);
enum BufError put_str4_to_offset(struct BitBuf *ptr, const uint32_t offset, const char str[4]);
enum BufError put_str4(struct BitBuf *ptr, const char str[4]);
enum BufError put_counted_str_to_offset(struct BitBuf *ptr, const uint32_t offset, const char *str, const uint32_t len);
enum BufError put_counted_str(struct BitBuf *ptr, const char *str, const uint32_t len);
struct MoovInfo {
uint8_t profile_idc;
uint8_t level_idc;
uint8_t *sps;
uint16_t sps_length;
uint8_t *pps;
uint16_t pps_length;
uint16_t width;
uint16_t height;
uint32_t horizontal_resolution;
uint32_t vertical_resolution;
uint32_t creation_time;
uint32_t timescale;
};
enum BufError write_header(struct BitBuf *ptr, struct MoovInfo *moov_info);
extern uint32_t pos_sequence_number;
extern uint32_t pos_base_data_offset;
extern uint32_t pos_base_media_decode_time;
struct SampleInfo {
uint32_t duration;
uint32_t decode_time;
uint32_t composition_time;
uint32_t composition_offset;
uint32_t size;
uint32_t flags;
};
enum BufError write_mdat(struct BitBuf *ptr, const uint8_t* data, const uint32_t origlen, const uint32_t len);
enum BufError write_moof(struct BitBuf *ptr,
const uint32_t sequence_number,
const uint64_t base_data_offset,
const uint64_t base_media_decode_time,
const uint32_t default_sample_duration,
const struct SampleInfo *samples_info, const uint32_t samples_info_len);
enum NalUnitType { // Table 7-1 NAL unit type codes
NalUnitType_Unspecified = 0, // Unspecified
NalUnitType_CodedSliceNonIdr = 1, // Coded slice of a non-IDR picture
NalUnitType_CodedSliceDataPartitionA = 2, // Coded slice data partition A
NalUnitType_CodedSliceDataPartitionB = 3, // Coded slice data partition B
NalUnitType_CodedSliceDataPartitionC = 4, // Coded slice data partition C
NalUnitType_CodedSliceIdr = 5, // Coded slice of an IDR picture
NalUnitType_SEI = 6, // Supplemental enhancement information (SEI)
NalUnitType_SPS = 7, // Sequence parameter set
NalUnitType_PPS = 8, // Picture parameter set
NalUnitType_AUD = 9, // Access unit delimiter
NalUnitType_EndOfSequence = 10, // End of sequence
NalUnitType_EndOfStream = 11, // End of stream
NalUnitType_Filler = 12, // Filler data
NalUnitType_SpsExt = 13, // Sequence parameter set extension
// 14..18 // Reserved
NalUnitType_CodedSliceAux = 19, // Coded slice of an auxiliary coded picture without partitioning
// 20..23 // Reserved
// 24..31 // Unspecified
};
struct NAL {
char *data;
uint64_t data_size;
uint32_t picture_order_count;
// NAL header
bool forbidden_zero_bit;
uint8_t ref_idc;
uint8_t unit_type_value;
enum NalUnitType unit_type;
};
static inline const char* nal_type_to_str(const enum NalUnitType nal_type) {
switch (nal_type) {
case NalUnitType_Unspecified: return "Unspecified";
case NalUnitType_CodedSliceNonIdr: return "CodedSliceNonIdr";
case NalUnitType_CodedSliceDataPartitionA: return "CodedSliceDataPartitionA";
case NalUnitType_CodedSliceDataPartitionB: return "CodedSliceDataPartitionB";
case NalUnitType_CodedSliceDataPartitionC: return "CodedSliceDataPartitionC";
case NalUnitType_CodedSliceIdr: return "CodedSliceIdr";
case NalUnitType_SEI: return "SEI";
case NalUnitType_SPS: return "SPS";
case NalUnitType_PPS: return "PPS";
case NalUnitType_AUD: return "AUD";
case NalUnitType_EndOfSequence: return "EndOfSequence";
case NalUnitType_EndOfStream: return "EndOfStream";
case NalUnitType_Filler: return "Filler";
case NalUnitType_SpsExt: return "SpsExt";
case NalUnitType_CodedSliceAux: return "CodedSliceAux";
default: return "Unknown";
}
}
static inline void nal_parse_header(struct NAL *nal, const char first_byte) {
nal->forbidden_zero_bit = ((first_byte & 0x80) >> 7) == 1;
nal->ref_idc = (first_byte & 0x60) >> 5;
nal->unit_type = (enum NalUnitType) ((first_byte & 0x1f) >> 0);
}
static inline bool nal_chk4(const uint8_t *buf, const uint32_t offset) {
if (buf[offset] == 0x00 && buf[offset+1] == 0x00 && buf[offset+2] == 0x01) { return true; }
if (buf[offset] == 0x00 && buf[offset+1] == 0x00 && buf[offset+2] == 0x00 && buf[offset+3] == 0x01) { return true; }
return false;
}
static inline bool nal_chk3(const uint8_t *buf, const uint32_t offset) {
if (buf[offset] == 0x00 && buf[offset+1] == 0x00 && buf[offset+2] == 0x01) { return true; }
return false;
}
extern uint32_t default_sample_size;
struct Mp4State {
bool header_sent;
uint32_t sequence_number;
uint64_t base_data_offset;
uint64_t base_media_decode_time;
uint32_t default_sample_duration;
uint32_t nals_count;
};
struct Mp4Context {
char buf_sps[128];
uint16_t buf_sps_len;
char buf_pps[128];
uint16_t buf_pps_len;
uint16_t w, h, framerate;
struct BitBuf buf_header;
struct BitBuf buf_moof;
struct BitBuf buf_mdat;
};
enum BufError set_slice(struct Mp4Context *ctx, const uint8_t* nal_data, const uint32_t origlen, const uint32_t nal_len, const enum NalUnitType unit_type);
void set_sps(struct Mp4Context *ctx, const uint8_t* nal_data, const uint32_t nal_len);
void set_pps(struct Mp4Context *ctx, const uint8_t* nal_data, const uint32_t nal_len);
enum BufError get_header(struct Mp4Context *ctx, struct BitBuf *ptr);
enum BufError set_mp4_state(struct Mp4Context *ctx, struct Mp4State *state);
enum BufError get_moof(struct Mp4Context *ctx, struct BitBuf *ptr);
enum BufError get_mdat(struct Mp4Context *ctx, struct BitBuf *ptr);
#ifdef __cplusplus
} // extern C
#endif

@ -0,0 +1,193 @@
#include "mp4.h"
#define chk_ptr if (!ptr) return BUF_INCORRECT;
#define chk_realloc { enum BufError err; err = try_to_realloc(ptr, pos); if (err != BUF_OK) return err; }
char* buf_error_to_str(const enum BufError err) {
switch (err) {
case BUF_OK: return "BUF_OK";
case BUF_ENDOFBUF_ERROR: return "BUF_ENDOFBUF_ERROR";
case BUF_MALLOC_ERROR: return "BUF_MALLOC_ERROR";
case BUF_INCORRECT: return "BUF_INCORRECT";
default: { static char str[32]; sprintf(str, "Unknown(%d)", err); return str; }
}
}
enum BufError try_to_realloc(struct BitBuf *ptr, const uint32_t min_size) {
chk_ptr
uint32_t new_size = ptr->size + min_size + 1024;
char* new_buf = realloc(ptr->buf, new_size);
if (new_buf == NULL) return BUF_MALLOC_ERROR;
ptr->buf = new_buf;
ptr->size = new_size;
return BUF_OK;
}
enum BufError put_skip(struct BitBuf *ptr, const uint32_t count) {
chk_ptr
uint32_t pos = ptr->offset + count;
if (pos >= ptr->size) chk_realloc
for (uint32_t i = 0; i < count; i++) ptr->buf[ptr->offset + i] = 0;
ptr->offset = pos;
return BUF_OK;
}
enum BufError put_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint8_t* data, const uint32_t size) {
chk_ptr
uint32_t pos = offset + size;
if (pos >= ptr->size) chk_realloc
for (uint32_t i = 0; i < size; i++) ptr->buf[offset + i] = data[i];
return BUF_OK;
}
enum BufError put(struct BitBuf *ptr, const uint8_t* data, const uint32_t size) {
chk_ptr
enum BufError err = put_to_offset(ptr, ptr->offset, data, size); chk_err
ptr->offset += size;
return BUF_OK;
}
enum BufError put_u8_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint8_t val) {
chk_ptr
uint32_t pos = offset + sizeof(uint8_t);
if (pos >= ptr->size) chk_realloc
ptr->buf[offset + 0] = val & 0xff;
return BUF_OK;
}
enum BufError put_u8(struct BitBuf *ptr, uint8_t val) {
chk_ptr
enum BufError err = put_u8_to_offset(ptr, ptr->offset, val); chk_err
ptr->offset += sizeof(uint8_t);
return BUF_OK;
}
enum BufError put_u16_be_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint16_t val) {
chk_ptr
uint32_t pos = offset + sizeof(uint16_t);
if (pos >= ptr->size) chk_realloc
ptr->buf[offset + 0] = (val >> 8) & 0xff;
ptr->buf[offset + 1] = (val >> 0) & 0xff;
return BUF_OK;
}
enum BufError put_u16_be(struct BitBuf *ptr, const uint16_t val) {
chk_ptr
enum BufError err = put_u16_be_to_offset(ptr, ptr->offset, val); chk_err
ptr->offset += sizeof(uint16_t);
return BUF_OK;
}
enum BufError put_u16_le_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint16_t val) {
chk_ptr
uint32_t pos = offset + sizeof(uint16_t);
if (pos >= ptr->size) chk_realloc
ptr->buf[offset + 0] = (val >> 0) & 0xff;
ptr->buf[offset + 1] = (val >> 8) & 0xff;
return BUF_OK;
}
enum BufError put_u16_le(struct BitBuf *ptr, const uint16_t val) {
chk_ptr
enum BufError err = put_u16_le_to_offset(ptr, ptr->offset, val); chk_err
ptr->offset += sizeof(uint16_t);
return BUF_OK;
}
enum BufError put_u32_be_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint32_t val) {
chk_ptr
uint32_t pos = offset + sizeof(uint32_t);
if (pos >= ptr->size) chk_realloc
ptr->buf[offset + 0] = (val >> 24) & 0xff;
ptr->buf[offset + 1] = (val >> 16) & 0xff;
ptr->buf[offset + 2] = (val >> 8) & 0xff;
ptr->buf[offset + 3] = (val >> 0) & 0xff;
return BUF_OK;
}
enum BufError put_u32_be(struct BitBuf *ptr, const uint32_t val) {
chk_ptr
enum BufError err = put_u32_be_to_offset(ptr, ptr->offset, val); chk_err
ptr->offset += sizeof(uint32_t);
return BUF_OK;
}
enum BufError put_i32_be(struct BitBuf *ptr, const int32_t val) {
chk_ptr
enum BufError err = put_u32_be_to_offset(ptr, ptr->offset, val); chk_err
ptr->offset += sizeof(int32_t);
return BUF_OK;
}
enum BufError put_u64_be_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint64_t val) {
chk_ptr
uint32_t pos = offset + sizeof(uint64_t);
if (pos > ptr->size) chk_realloc
ptr->buf[offset + 0] = (val >> 56) & 0xff;
ptr->buf[offset + 1] = (val >> 48) & 0xff;
ptr->buf[offset + 2] = (val >> 40) & 0xff;
ptr->buf[offset + 3] = (val >> 32) & 0xff;
ptr->buf[offset + 4] = (val >> 24) & 0xff;
ptr->buf[offset + 5] = (val >> 16) & 0xff;
ptr->buf[offset + 6] = (val >> 8) & 0xff;
ptr->buf[offset + 7] = (val >> 0) & 0xff;
return BUF_OK;
}
enum BufError put_u64_be(struct BitBuf *ptr, const uint64_t val) {
chk_ptr
enum BufError err = put_u64_be_to_offset(ptr, ptr->offset, val); chk_err
ptr->offset += sizeof(uint64_t);
return BUF_OK;
}
enum BufError put_u32_le_to_offset(struct BitBuf *ptr, const uint32_t offset, const uint32_t val) {
chk_ptr
uint32_t pos = offset + 4;
if (pos >= ptr->size) chk_realloc
ptr->buf[offset + 0] = (val >> 0) & 0xff;
ptr->buf[offset + 1] = (val >> 8) & 0xff;
ptr->buf[offset + 2] = (val >> 16) & 0xff;
ptr->buf[offset + 3] = (val >> 24) & 0xff;
return BUF_OK;
}
enum BufError put_u32_le(struct BitBuf *ptr, const uint32_t val) {
chk_ptr
enum BufError err = put_u32_le_to_offset(ptr, ptr->offset, val); chk_err
ptr->offset += sizeof(uint32_t);
return BUF_OK;
}
enum BufError put_str4_to_offset(struct BitBuf *ptr, const uint32_t offset, const char str[4]) {
chk_ptr
uint32_t pos = offset + 4;
if (pos >= ptr->size) chk_realloc
for (uint8_t i = 0; i < 4; i++) { ptr->buf[offset + i] = str[i]; }
return BUF_OK;
}
enum BufError put_str4(struct BitBuf *ptr, const char str[4]) {
chk_ptr
enum BufError err = put_str4_to_offset(ptr, ptr->offset, str); chk_err
ptr->offset += 4;
return BUF_OK;
}
enum BufError put_counted_str_to_offset(struct BitBuf *ptr, const uint32_t offset, const char *str, const uint32_t len) {
chk_ptr
uint32_t pos = offset + len + 1;
if (pos >= ptr->size) chk_realloc
for (uint32_t i = 0; i < len+1; i++) { ptr->buf[offset + i] = str[i]; }
ptr->buf[pos] = 0;
return BUF_OK;
}
enum BufError put_counted_str(struct BitBuf *ptr, const char *str, const uint32_t len) {
chk_ptr
enum BufError err = put_counted_str_to_offset(ptr, ptr->offset, str, len); chk_err
ptr->offset += len+1;
return BUF_OK;
}
// enum BufError hexStr(struct BitBuf *ptr, char *str) : string {
// let str = '';
// for(let i = 0; i < this.offset; i++) {
// if (i % 40 === 0) str += '\n';
// if (i % 4 === 0 && i+1 < this.data.length) {
// if (i > 0 && i % 40 !== 0) str += ' ';
// str += '0x';
// }
// str += decimalToHex(this.data[i]);
// }
// return str;
// }

@ -0,0 +1,194 @@
#include "mp4.h"
#include <string.h>
uint32_t pos_sequence_number = 0;
uint32_t pos_base_data_offset = 0;
uint32_t pos_base_media_decode_time = 0;
struct DataOffsetPos {
bool data_offset_present;
uint32_t offset;
};
enum BufError write_mfhd(struct BitBuf *ptr, const uint32_t sequence_number);
enum BufError write_traf(struct BitBuf *ptr,
const uint32_t sequence_number,
const uint64_t base_data_offset,
const uint64_t base_media_decode_time,
const uint32_t default_sample_duration,
const struct SampleInfo *samples_info, const uint32_t samples_info_len,
struct DataOffsetPos *data_offset);
enum BufError write_tfhd(struct BitBuf *ptr,
const uint32_t sequence_number,
const uint64_t base_data_offset,
const uint64_t base_media_decode_time,
const uint32_t default_sample_size,
const uint32_t default_sample_duration,
const struct SampleInfo *samples_info, const uint32_t samples_info_len,
struct DataOffsetPos *data_offset);
enum BufError write_tfdt(struct BitBuf *ptr, const uint64_t base_media_decode_time);
enum BufError write_trun(struct BitBuf *ptr,
const struct SampleInfo *samples_info, const uint32_t samples_info_count,
struct DataOffsetPos *data_offset);
enum BufError write_mdat(struct BitBuf *ptr, const uint8_t* data, const uint32_t origlen, const uint32_t len) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "mdat"); chk_err
err = put_u32_be(ptr, origlen); chk_err // todo
// printf(" write_mdat: "); for (int i = 0; i < 32; ++i) printf(" 0x%02hhX", data[i]); printf("\n");
err = put(ptr, data, len); chk_err
// printf("mdat len %d ptr->offset %d start_atom: %d \n", len, ptr->offset, start_atom);
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_moof(struct BitBuf *ptr,
const uint32_t sequence_number,
const uint64_t base_data_offset,
const uint64_t base_media_decode_time,
const uint32_t default_sample_duration,
const struct SampleInfo *samples_info, const uint32_t samples_info_len)
{
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "moof"); chk_err
err = write_mfhd(ptr, sequence_number); chk_err
struct DataOffsetPos data_offset;
data_offset.offset = 0;
err = write_traf(ptr, sequence_number, base_data_offset, base_media_decode_time, default_sample_duration, samples_info, samples_info_len, &data_offset); chk_err
if (data_offset.data_offset_present)
err = put_u32_be_to_offset(ptr, data_offset.offset, ptr->offset + 4 /*mdat size*/ + 4 /*mdat id*/); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_mfhd(struct BitBuf *ptr, const uint32_t sequence_number) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "mfhd"); chk_err
err = put_u8(ptr, 0); // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // 3 flags
pos_sequence_number = ptr->offset;
err = put_u32_be(ptr, sequence_number); chk_err // 4 sequence_number
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_traf(struct BitBuf *ptr,
const uint32_t sequence_number,
const uint64_t base_data_offset,
const uint64_t base_media_decode_time,
const uint32_t default_sample_duration,
const struct SampleInfo *samples_info, const uint32_t samples_info_len,
struct DataOffsetPos *data_offset)
{
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "traf"); chk_err
err = write_tfhd(ptr, sequence_number, base_data_offset, base_media_decode_time, samples_info[0].size, default_sample_duration, samples_info, samples_info_len, data_offset); chk_err
err = write_tfdt(ptr, base_media_decode_time); chk_err
err = write_trun(ptr, samples_info, samples_info_len, data_offset); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_tfhd(struct BitBuf *ptr,
const uint32_t sequence_number,
const uint64_t base_data_offset,
const uint64_t base_media_decode_time,
const uint32_t default_sample_size,
const uint32_t default_sample_duration,
const struct SampleInfo *samples_info, const uint32_t samples_info_len,
struct DataOffsetPos *data_offset)
{
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "tfhd"); chk_err
err = put_u8(ptr, 0); chk_err // 1 byte version
uint64_t flags = 0x0;
const bool base_data_offset_present = false;
const bool sample_description_index_present = false;
const bool default_sample_duration_present = true;
const bool default_sample_size_present = true;
const bool default_sample_flags_present = true;
const bool duration_is_empty = false;
const bool default_base_is_moof = false;
if (base_data_offset_present) { flags = flags | 0x000001; } // base-data-offset-present
if (sample_description_index_present) { flags = flags | 0x000002; } // sample-description-index-present
if (default_sample_duration_present) { flags = flags | 0x000008; } // default-sample-duration-present
if (default_sample_size_present) { flags = flags | 0x000010; } // default-sample-size-present
if (default_sample_flags_present) { flags = flags | 0x000020; } // default-sample-flags-present
if (duration_is_empty) { flags = flags | 0x010000; } // duration-is-empty
if (default_base_is_moof) { flags = flags | 0x020000; } // default-base-is-moof
// buf.put_u8(0); buf.put_u8(0); buf.put_u8(0x39); // 3 flags
// println!("tfhd flags: 0x{:06x} 0x{:02x}: 0x{:02x}: 0x{:02x}", flags, (flags >> 16) as u8, (flags >> 8) as u8, (flags >> 0) as u8);
err = put_u8(ptr, flags >> 16); chk_err; err = put_u8(ptr, flags >> 8); chk_err; err = put_u8(ptr, flags >> 0); chk_err // 3 flags
err = put_u32_be(ptr, 1); chk_err // 4 track_ID
if (base_data_offset_present) { pos_base_data_offset = ptr->offset; err = put_u64_be(ptr, base_data_offset); chk_err }
// if sample_description_index_present { buf.put_u32_be(0); } // 4 default_sample_description_index
if (default_sample_duration_present) { err = put_u32_be(ptr, default_sample_duration); chk_err }
if (default_sample_size_present) { err = put_u32_be(ptr, default_sample_size); chk_err }
if (default_sample_flags_present) { err = put_u32_be(ptr, 16842752); chk_err }
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_tfdt(struct BitBuf *ptr, const uint64_t base_media_decode_time) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "tfdt"); chk_err
err = put_u8(ptr, 1); // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // 3 flags
pos_base_media_decode_time = ptr->offset;
err = put_u64_be(ptr, base_media_decode_time); chk_err // 4 baseMediaDecodeTime
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_trun(struct BitBuf *ptr,
const struct SampleInfo *samples_info, const uint32_t samples_info_count,
struct DataOffsetPos *data_offset)
{
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "trun"); chk_err
err = put_u8(ptr, 0); chk_err // 1 version
const bool data_offset_present = true;
const bool first_sample_flags_present = false;
const bool sample_duration_present = true;
const bool sample_size_present = true;
const bool sample_flags_present = true;
const bool sample_composition_time_offsets_present = true;
{
uint64_t flags = 0x0;
if (data_offset_present) { flags = flags | 0x000001; } // 0x000001 data-offset-present.
if (first_sample_flags_present) { flags = flags | 0x000004; } // 0x000004 first-sample-flags-present
if (sample_duration_present) { flags = flags | 0x000100; } // 0x000100 sample-duration-present
if (sample_size_present) { flags = flags | 0x000200; } // 0x000200 sample-size-present
if (sample_flags_present) { flags = flags | 0x000400; } // 0x000400 sample-flags-present
if (sample_composition_time_offsets_present) { flags = flags | 0x000800; } // 0x000800 sample-composition-time-offsets-present
// println!("trup flags: 0x{:06x} 0x{:02x}: 0x{:02x}: 0x{:02x}", flags, (flags >> 16) as u8, (flags >> 8) as u8, (flags >> 0) as u8);
err = put_u8(ptr, flags >> 16); chk_err; err = put_u8(ptr, flags >> 8); chk_err; err = put_u8(ptr, flags >> 0); chk_err // 3 flags
}
err = put_u32_be(ptr, samples_info_count); chk_err // 4 sample_count
data_offset->data_offset_present = data_offset_present;
data_offset->offset = ptr->offset; // save pointer to this place. we will change size after moof atom will created
if (data_offset_present) { err = put_i32_be(ptr, 0); chk_err } // 4 fake data_offset
if (first_sample_flags_present) { err = put_u32_be(ptr, 33554432); chk_err } // 4 first_sample_flags
for (uint32_t i = 0; i < samples_info_count; ++i) {
const struct SampleInfo sample_info = samples_info[i];
if (sample_duration_present) { err = put_u32_be(ptr, sample_info.duration); chk_err } // 4 sample_duration
if (sample_size_present) { err = put_u32_be(ptr, sample_info.size); chk_err } // 4 sample_size
if (sample_flags_present) { err = put_u32_be(ptr, sample_info.flags); chk_err } // 4 sample_flags
if (sample_composition_time_offsets_present) {
// if version == 0 { err = put_u32_be(ptr, sample_info.composition_offset as u32); chk_err }
// else
{ err = put_i32_be(ptr, sample_info.composition_offset); chk_err }
}
}
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}

@ -0,0 +1,420 @@
#include "mp4.h"
#include <string.h>
enum BufError write_ftyp(struct BitBuf *ptr);
enum BufError write_moov(struct BitBuf *ptr, const struct MoovInfo *moov_info);
enum BufError write_mvhd(struct BitBuf *ptr, const struct MoovInfo *moov_info);
enum BufError write_trak(struct BitBuf *ptr, const struct MoovInfo *moov_info);
enum BufError write_tkhd(struct BitBuf *ptr, const struct MoovInfo *moov_info);
enum BufError write_mdia(struct BitBuf *ptr, const struct MoovInfo *moov_info);
enum BufError write_mdhd(struct BitBuf *ptr, const struct MoovInfo *moov_info);
enum BufError write_minf(struct BitBuf *ptr, const struct MoovInfo *moov_info);
enum BufError write_dinf(struct BitBuf *ptr);
enum BufError write_dref(struct BitBuf *ptr);
enum BufError write_url(struct BitBuf *ptr);
enum BufError write_vmhd(struct BitBuf *ptr);
enum BufError write_stbl(struct BitBuf *ptr, const struct MoovInfo *moov_info);
enum BufError write_stsd(struct BitBuf *ptr, const struct MoovInfo *moov_info);
enum BufError write_avc1(struct BitBuf *ptr, const struct MoovInfo *moov_info);
enum BufError write_avcC(struct BitBuf *ptr, const struct MoovInfo *moov_info);
enum BufError write_stts(struct BitBuf *ptr);
enum BufError write_stsc(struct BitBuf *ptr);
enum BufError write_stsz(struct BitBuf *ptr);
enum BufError write_stco(struct BitBuf *ptr);
enum BufError write_mvex(struct BitBuf *ptr);
enum BufError write_trex(struct BitBuf *ptr);
enum BufError write_udta(struct BitBuf *ptr);
enum BufError write_meta(struct BitBuf *ptr);
enum BufError write_hdlr(struct BitBuf *ptr, const char name[4], const char manufacturer[4], const char *value, const uint32_t value_len);
enum BufError write_ilst(struct BitBuf *ptr, const uint8_t *array, const uint32_t len);
enum BufError write_header(struct BitBuf *ptr, struct MoovInfo *moov_info) {
enum BufError err;
err = write_ftyp(ptr); chk_err
err = write_moov(ptr, moov_info); chk_err
return BUF_OK;
}
enum BufError write_ftyp(struct BitBuf *ptr) {
enum BufError err;
// atom header <fake size><id>
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "ftyp"); chk_err
err = put_str4(ptr, "isom"); chk_err // major_brand
err = put_u32_be(ptr, 0x00000200); chk_err // minor_version
err = put_str4(ptr, "isom"); chk_err
err = put_str4(ptr, "iso2"); chk_err
err = put_str4(ptr, "avc1"); chk_err
err = put_str4(ptr, "iso6"); chk_err
err = put_str4(ptr, "mp41"); chk_err
// write atom size
uint32_t atom_size = ptr->offset - start_atom;
err = put_u32_be_to_offset(ptr, start_atom, atom_size); chk_err
return BUF_OK;
}
enum BufError write_moov(struct BitBuf *ptr, const struct MoovInfo *moov_info) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "moov"); chk_err
err = write_mvhd(ptr, moov_info); chk_err
err = write_trak(ptr, moov_info); chk_err
err = write_mvex(ptr); chk_err
err = write_udta(ptr); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_mvhd(struct BitBuf *ptr, const struct MoovInfo *moov_info) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "mvhd"); chk_err
err = put_u8(ptr, 0); chk_err // 1 version
err = put_u8(ptr, 0); chk_err; err=put_u8(ptr, 0);chk_err; err=put_u8(ptr, 0);chk_err // 3 flags
err = put_u32_be(ptr, moov_info->creation_time); chk_err // 4 creation_time
err = put_u32_be(ptr, 0); chk_err // 4 modification_time
err = put_u32_be(ptr, moov_info->timescale); chk_err // 4 timescale
err = put_u32_be(ptr, 0); chk_err // 4 duration
err = put_u32_be(ptr, 65536); chk_err // 4 preferred rate
err = put_u16_le(ptr, 1); chk_err // 2 preferred volume
err = put_skip(ptr, 10); chk_err // 10 reserved
{ // 36 matrix
err = put_u32_be(ptr, 65536); chk_err
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 65536); chk_err
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 1073741824); chk_err
}
err = put_u32_be(ptr, 0); chk_err // 4 Preview time
err = put_u32_be(ptr, 0); chk_err // 4 Preview duration
err = put_u32_be(ptr, 0); chk_err // 4 Poster time
err = put_u32_be(ptr, 0); chk_err // 4 Selection time
err = put_u32_be(ptr, 0); chk_err // 4 Selection duration
err = put_u32_be(ptr, 0); chk_err // 4 Current time
err = put_u32_be(ptr, 2); chk_err // 4 Next track ID
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_trak(struct BitBuf *ptr, const struct MoovInfo *moov_info) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "trak"); chk_err
err = write_tkhd(ptr, moov_info); chk_err
err = write_mdia(ptr, moov_info); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_tkhd(struct BitBuf *ptr, const struct MoovInfo *moov_info) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "tkhd"); chk_err
err = put_u8(ptr, 0); // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 3); chk_err // 3 flags
err = put_u32_be(ptr, moov_info->creation_time); // 4 creation_time
err = put_u32_be(ptr, 0); // 4 modification_time
err = put_u32_be(ptr, 1); // 4 track id
err = put_u32_be(ptr, 0); // 4 reserved
err = put_u32_be(ptr, 0); // 4 duration
err = put_skip(ptr, 8); // 8 reserved
err = put_u16_be(ptr, 0); // 2 layer
err = put_u16_be(ptr, 0); // 2 Alternate group
err = put_u16_be(ptr, 0); // 2 Volume
err = put_u16_be(ptr, 0); // 2 Reserved
{ // 36 Matrix structure
err = put_u32_be(ptr, 65536); chk_err
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 65536); chk_err
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 1073741824); chk_err
}
err = put_u32_be(ptr, moov_info->width * 65536); chk_err // 4 Track width
err = put_u32_be(ptr, moov_info->height * 65536); chk_err // 4 Track height
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_mdia(struct BitBuf *ptr, const struct MoovInfo *moov_info) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "mdia"); chk_err
err = write_mdhd(ptr, moov_info); chk_err
char *str = "VideoHandler";
err = write_hdlr(ptr, "vide", "\0\0\0\0", str, strlen(str)); chk_err
err = write_minf(ptr, moov_info); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_mdhd(struct BitBuf *ptr, const struct MoovInfo *moov_info) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "mdhd"); chk_err
err = put_u8(ptr, 0); // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // 3 flags
err = put_u32_be(ptr, 0); chk_err // 4 creation_time
err = put_u32_be(ptr, 0); chk_err // 4 modification_time
err = put_u32_be(ptr, moov_info->timescale); chk_err // 4 timescale
err = put_u32_be(ptr, 0); chk_err // 4 duration
err = put_u16_be(ptr, 21956); chk_err // 2 language
err = put_u16_be(ptr, 0); chk_err // 2 quality
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_minf(struct BitBuf *ptr, const struct MoovInfo *moov_info) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "minf"); chk_err
err = write_vmhd(ptr); chk_err
err = write_dinf(ptr); chk_err
err = write_stbl(ptr, moov_info); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_dinf(struct BitBuf *ptr) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "dinf"); chk_err
err = write_dref(ptr); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_dref(struct BitBuf *ptr) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "dref"); chk_err
err = put_u8(ptr, 0); chk_err // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // 3 flags
err = put_u32_be(ptr, 1); chk_err // 4 Component flags mask
err = write_url(ptr); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_url(struct BitBuf *ptr) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "url "); chk_err
err = put_u8(ptr, 0); chk_err // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 1); chk_err // 3 flags
//err = put_u8(ptr, 0); chk_err // <counted string> end
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_vmhd(struct BitBuf *ptr) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "vmhd"); chk_err
err = put_u8(ptr, 0); chk_err // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 1); chk_err // 3 flags
err = put_u16_be(ptr, 0); chk_err // 2 Graphics mode
err = put_u16_be(ptr, 0); chk_err // 2 Opcolor
err = put_u16_be(ptr, 0); chk_err // 2 Opcolor
err = put_u16_be(ptr, 0); chk_err // 2 Opcolor
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_stbl(struct BitBuf *ptr, const struct MoovInfo *moov_info) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "stbl"); chk_err
err = write_stsd(ptr, moov_info); chk_err
err = write_stts(ptr); chk_err
err = write_stsc(ptr); chk_err
err = write_stsz(ptr); chk_err
err = write_stco(ptr); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_stsd(struct BitBuf *ptr, const struct MoovInfo *moov_info) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "stsd"); chk_err
err = put_u8(ptr, 0); chk_err // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // 3 flags
err = put_u32_be(ptr, 1); chk_err // 4 Number of entries
err = write_avc1(ptr, moov_info); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_avc1(struct BitBuf *ptr, const struct MoovInfo *moov_info) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "avc1"); chk_err
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // reserved
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // reserved
err = put_u16_be(ptr, 1); chk_err // data_reference_index
err = put_u16_be(ptr, 0); chk_err // pre_defined
err = put_u16_be(ptr, 0); chk_err // reserved
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 0); chk_err
err = put_u32_be(ptr, 0); chk_err // pre_defined
err = put_u16_be(ptr, moov_info->width); chk_err // 2 width
err = put_u16_be(ptr, moov_info->height); chk_err // 2 height
err = put_u32_be(ptr, moov_info->horizontal_resolution); chk_err // 4 horizontal_resolution
err = put_u32_be(ptr, moov_info->vertical_resolution); chk_err // 4 vertical_resolution
err = put_u32_be(ptr, 0); chk_err // reserved
err = put_u16_be(ptr, 1); chk_err // 2 frame_count
err = put_u8(ptr, 0); chk_err
// uint8_t *compressorname = { 0, 0, 0, 0, // dailymotion/hls.js
// 0, 0, 0, 0,
// 0, 0, 0, 0,
// 0, 0, 0, 0,
// 0, 0, 0, 0,
// 0, 0, 0, 0,
// 0, 0, 0, 0,
// 0, 0, 0 };
char compressorname[50] = "OpenIPC project ";
err = put(ptr, (uint8_t *) compressorname, 31); chk_err // compressorname
err = put_u16_be(ptr, 24); chk_err // 2 depth
err = put_u16_be(ptr, 0xffff); chk_err // 2 color_table_id
err = write_avcC(ptr, moov_info); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_avcC(struct BitBuf *ptr, const struct MoovInfo *moov_info) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "avcC"); chk_err
err = put_u8(ptr, 1); chk_err // 1 version
err = put_u8(ptr, moov_info->sps[1]); chk_err // 1 profile
err = put_u8(ptr, moov_info->sps[2]); chk_err // 1 compatibility
err = put_u8(ptr, moov_info->sps[3]); chk_err // 1 level
err = put_u8(ptr, 0xFF); chk_err // 6 bits reserved (111111) + 2 bits nal size length - 1 (11)
err = put_u8(ptr, 0xE1); chk_err // 3 bits reserved (111) + 5 bits number of sps (00001)
err = put_u16_be(ptr, moov_info->sps_length); chk_err
err = put(ptr, (const uint8_t *) moov_info->sps, moov_info->sps_length); chk_err // SPS
err = put_u8(ptr, 1); chk_err // 1 num pps
err = put_u16_be(ptr, moov_info->pps_length); chk_err
err = put(ptr, (const uint8_t *)moov_info->pps, moov_info->pps_length); chk_err // pps
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_stts(struct BitBuf *ptr) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "stts"); chk_err
err = put_u8(ptr, 0); chk_err // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // 3 flags
err = put_u32_be(ptr, 0); chk_err // Number of entries
// Time-to-sample table
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_stsc(struct BitBuf *ptr) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "stsc"); chk_err
err = put_u8(ptr, 0); chk_err // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // 3 flags
err = put_u32_be(ptr, 0); chk_err // Number of entries
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_stsz(struct BitBuf *ptr) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "stsz"); chk_err
err = put_u8(ptr, 0); chk_err // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // 3 flags
err = put_u32_be(ptr, 0); chk_err // Sample size
err = put_u32_be(ptr, 0); chk_err // Number of entries
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_stco(struct BitBuf *ptr) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "stco"); chk_err
err = put_u8(ptr, 0); chk_err // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // 3 flags
err = put_u32_be(ptr, 0); chk_err // Number of entries
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_mvex(struct BitBuf *ptr) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "mvex"); chk_err
err = write_trex(ptr); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_trex(struct BitBuf *ptr) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "trex"); chk_err
err = put_u8(ptr, 0); chk_err // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // 3 flags
err = put_u32_be(ptr, 1); chk_err // track_ID
err = put_u32_be(ptr, 1); chk_err // default_sample_description_index
err = put_u32_be(ptr, 0); chk_err // default_sample_duration
err = put_u32_be(ptr, 0); chk_err // default_sample_size
err = put_u32_be(ptr, 0); chk_err // default_sample_flags
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_udta(struct BitBuf *ptr) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "udta"); chk_err
err = write_meta(ptr); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_meta(struct BitBuf *ptr) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "meta"); chk_err
err = put_u8(ptr, 0); chk_err // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // 3 flags
err = write_hdlr(ptr, "mdir", "appl", "", 0); chk_err
uint8_t array[37] = {0,0,0,37,169,116,111,111,0,0,0,29,100,97,116,97,0,0,0,1,0,0,0,0,76,97,118,102,53,55,46,56,51,46,49,48,48};
err = write_ilst(ptr, array, 37); chk_err
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_hdlr(struct BitBuf *ptr, const char name[4], const char manufacturer[4], const char *value, const uint32_t value_len) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "hdlr"); chk_err
err = put_u8(ptr, 0); chk_err // 1 version
err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err; err = put_u8(ptr, 0); chk_err // 3 flags
err = put_u32_be(ptr, 0); chk_err // 4 Predefined
err = put_str4(ptr, name); chk_err // 4 Component subtype
err = put_str4(ptr, manufacturer); chk_err // 4 Component manufacturer
err = put_u32_be(ptr, 0); chk_err // 4 Component flags
err = put_u32_be(ptr, 0); chk_err // 4 Component flags mask
err = put_counted_str(ptr, value, value_len); chk_err // <counted string> Component name
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}
enum BufError write_ilst(struct BitBuf *ptr, const uint8_t *array, const uint32_t len) {
enum BufError err;
uint32_t start_atom = ptr->offset; err = put_u32_be(ptr, 0); chk_err; err = put_str4(ptr, "ilst"); chk_err
err = put(ptr, array, len); chk_err // <counted string> Component name
err = put_u32_be_to_offset(ptr, start_atom, ptr->offset - start_atom); chk_err
return BUF_OK;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,453 @@
/*
* H.264/HEVC hardware encoding using nvidia nvenc
* Copyright (c) 2016 Timo Rothenpieler <timo@rothenpieler.org>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <rfb/LogWriter.h>
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nvidia.h"
using namespace rfb;
static LogWriter vlog("nvidia");
#define FFNV_LOG_FUNC(logctx, msg, ...) vlog.info((msg), __VA_ARGS__)
#define FFNV_DEBUG_LOG_FUNC(logctx, msg, ...)
#include "dynlink_loader.h"
#define NUM_SURF 4
typedef struct NvencSurface
{
NV_ENC_INPUT_PTR input_surface;
int reg_idx;
int width;
int height;
int pitch;
NV_ENC_OUTPUT_PTR output_surface;
NV_ENC_BUFFER_FORMAT format;
} NvencSurface;
typedef struct NvencDynLoadFunctions
{
CudaFunctions *cuda_dl;
NvencFunctions *nvenc_dl;
void *nvenc_ctx;
NV_ENCODE_API_FUNCTION_LIST nvenc_funcs;
NV_ENC_INITIALIZE_PARAMS init_enc_parms;
NV_ENC_CONFIG enc_cfg;
CUdevice cu_dev;
CUcontext cu_ctx;
NvencSurface surf[NUM_SURF];
uint8_t cursurf;
} NvencDynLoadFunctions;
static NvencDynLoadFunctions nvenc;
/*
Recommended settings for streaming
Low-Latency High Quality preset
Rate control mode = Two-pass CBR
Very low VBV buffer size (Single frame)
No B Frames
Infinite GOP length
Adaptive Quantization enabled
*/
static int loadfuncs() {
int ret;
NVENCSTATUS err;
uint32_t nvenc_max_ver;
ret = cuda_load_functions(&nvenc.cuda_dl);
if (ret < 0)
return ret;
ret = nvenc_load_functions(&nvenc.nvenc_dl);
if (ret < 0)
return ret;
err = nvenc.nvenc_dl->NvEncodeAPIGetMaxSupportedVersion(&nvenc_max_ver);
if (err != NV_ENC_SUCCESS)
return -1;
vlog.info("Loaded nvenc version %u.%u", nvenc_max_ver >> 4, nvenc_max_ver & 0xf);
if ((NVENCAPI_MAJOR_VERSION << 4 | NVENCAPI_MINOR_VERSION) > nvenc_max_ver) {
vlog.error("Your Nvidia driver is too old. Nvenc %u.%u required",
NVENCAPI_MAJOR_VERSION, NVENCAPI_MINOR_VERSION);
return -1;
}
nvenc.nvenc_funcs.version = NV_ENCODE_API_FUNCTION_LIST_VER;
err = nvenc.nvenc_dl->NvEncodeAPICreateInstance(&nvenc.nvenc_funcs);
if (err != NV_ENC_SUCCESS)
return -1;
return 0;
}
static int nvenc_check_cap(NV_ENC_CAPS cap) {
NV_ENC_CAPS_PARAM params;
memset(&params, 0, sizeof(NV_ENC_CAPS_PARAM));
params.version = NV_ENC_CAPS_PARAM_VER;
params.capsToQuery = cap;
int ret, val = 0;
ret = nvenc.nvenc_funcs.nvEncGetEncodeCaps(nvenc.nvenc_ctx,
nvenc.init_enc_parms.encodeGUID,
&params, &val);
if (ret == NV_ENC_SUCCESS)
return val;
return 0;
}
static int setupdevice() {
int ret;
nvenc.init_enc_parms.encodeGUID = NV_ENC_CODEC_H264_GUID;
nvenc.init_enc_parms.presetGUID = NV_ENC_PRESET_P7_GUID;
ret = nvenc.cuda_dl->cuInit(0);
if (ret < 0)
return ret;
ret = nvenc.cuda_dl->cuDeviceGet(&nvenc.cu_dev, 0);
if (ret < 0)
return ret;
ret = nvenc.cuda_dl->cuCtxCreate(&nvenc.cu_ctx, CU_CTX_SCHED_BLOCKING_SYNC,
nvenc.cu_dev);
if (ret < 0)
return ret;
CUcontext dummy;
nvenc.cuda_dl->cuCtxPopCurrent(&dummy);
// cuda stream is NULL to use the default
// open session
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params;
memset(&params, 0, sizeof(NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS));
NVENCSTATUS err;
params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
params.apiVersion = NVENCAPI_VERSION;
params.device = nvenc.cu_ctx;
params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
err = nvenc.nvenc_funcs.nvEncOpenEncodeSessionEx(&params, &nvenc.nvenc_ctx);
if (err != NV_ENC_SUCCESS)
return -1;
// check caps
const int maxw = nvenc_check_cap(NV_ENC_CAPS_WIDTH_MAX);
const int maxh = nvenc_check_cap(NV_ENC_CAPS_HEIGHT_MAX);
const int minw = nvenc_check_cap(NV_ENC_CAPS_WIDTH_MIN);
const int minh = nvenc_check_cap(NV_ENC_CAPS_HEIGHT_MIN);
vlog.info("Max enc resolution %ux%u, min %ux%u", maxw, maxh, minw, minh);
return 0;
}
static int setupenc(const unsigned w, const unsigned h, const unsigned kbps,
const unsigned fps) {
NVENCSTATUS err;
nvenc.enc_cfg.version = NV_ENC_CONFIG_VER;
nvenc.init_enc_parms.version = NV_ENC_INITIALIZE_PARAMS_VER;
nvenc.init_enc_parms.darWidth =
nvenc.init_enc_parms.encodeWidth = w;
nvenc.init_enc_parms.darHeight =
nvenc.init_enc_parms.encodeHeight = h;
nvenc.init_enc_parms.frameRateNum = fps;
nvenc.init_enc_parms.frameRateDen = 1;
nvenc.init_enc_parms.encodeConfig = &nvenc.enc_cfg;
nvenc.init_enc_parms.tuningInfo = NV_ENC_TUNING_INFO_LOW_LATENCY;
NV_ENC_PRESET_CONFIG preset_cfg;
memset(&preset_cfg, 0, sizeof(NV_ENC_PRESET_CONFIG));
preset_cfg.version = NV_ENC_PRESET_CONFIG_VER;
preset_cfg.presetCfg.version = NV_ENC_CONFIG_VER;
err = nvenc.nvenc_funcs.nvEncGetEncodePresetConfigEx(nvenc.nvenc_ctx,
nvenc.init_enc_parms.encodeGUID,
nvenc.init_enc_parms.presetGUID,
nvenc.init_enc_parms.tuningInfo,
&preset_cfg);
if (err != NV_ENC_SUCCESS)
return -1;
memcpy(&nvenc.enc_cfg, &preset_cfg.presetCfg, sizeof(nvenc.enc_cfg));
nvenc.enc_cfg.version = NV_ENC_CONFIG_VER;
nvenc.init_enc_parms.enableEncodeAsync = 0;
nvenc.init_enc_parms.enablePTD = 1;
nvenc.enc_cfg.frameIntervalP = 0;
nvenc.enc_cfg.gopLength = 1;
// use 4 surfaces
// setup rate control
nvenc.enc_cfg.rcParams.multiPass = NV_ENC_TWO_PASS_FULL_RESOLUTION;
nvenc.enc_cfg.rcParams.averageBitRate = kbps * 1024;
nvenc.enc_cfg.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CBR;
nvenc.enc_cfg.rcParams.lowDelayKeyFrameScale = 1;
nvenc.enc_cfg.rcParams.enableAQ = 1;
nvenc.enc_cfg.rcParams.aqStrength = 4; // 1 - 15, 0 would be auto
nvenc.enc_cfg.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME;
// setup_codec_config
nvenc.enc_cfg.encodeCodecConfig.h264Config.h264VUIParameters.videoFullRangeFlag = 1;
nvenc.enc_cfg.encodeCodecConfig.h264Config.outputBufferingPeriodSEI = 1;
nvenc.enc_cfg.encodeCodecConfig.h264Config.adaptiveTransformMode = NV_ENC_H264_ADAPTIVE_TRANSFORM_ENABLE;
nvenc.enc_cfg.encodeCodecConfig.h264Config.fmoMode = NV_ENC_H264_FMO_DISABLE;
nvenc.enc_cfg.profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
nvenc.cuda_dl->cuCtxPushCurrent(nvenc.cu_ctx);
err = nvenc.nvenc_funcs.nvEncInitializeEncoder(nvenc.nvenc_ctx,
&nvenc.init_enc_parms);
if (err != NV_ENC_SUCCESS)
return -1;
// custream?
CUcontext dummy;
nvenc.cuda_dl->cuCtxPopCurrent(&dummy);
return 0;
}
static int setupsurf(const unsigned w, const unsigned h) {
nvenc.cuda_dl->cuCtxPushCurrent(nvenc.cu_ctx);
int i;
for (i = 0; i < NUM_SURF; i++) {
NVENCSTATUS err;
NV_ENC_CREATE_BITSTREAM_BUFFER allocOut;
memset(&allocOut, 0, sizeof(NV_ENC_CREATE_BITSTREAM_BUFFER));
allocOut.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER;
NV_ENC_CREATE_INPUT_BUFFER allocSurf;
memset(&allocSurf, 0, sizeof(NV_ENC_CREATE_INPUT_BUFFER));
nvenc.surf[i].format = NV_ENC_BUFFER_FORMAT_ARGB; // doesn't have RGBA!
allocSurf.version = NV_ENC_CREATE_INPUT_BUFFER_VER;
allocSurf.width = w;
allocSurf.height = h;
allocSurf.bufferFmt = nvenc.surf[i].format;
err = nvenc.nvenc_funcs.nvEncCreateInputBuffer(nvenc.nvenc_ctx, &allocSurf);
if (err != NV_ENC_SUCCESS)
return -1;
nvenc.surf[i].input_surface = allocSurf.inputBuffer;
nvenc.surf[i].width = allocSurf.width;
nvenc.surf[i].height = allocSurf.height;
// output
err = nvenc.nvenc_funcs.nvEncCreateBitstreamBuffer(nvenc.nvenc_ctx, &allocOut);
if (err != NV_ENC_SUCCESS)
return -1;
nvenc.surf[i].output_surface = allocOut.bitstreamBuffer;
}
CUcontext dummy;
nvenc.cuda_dl->cuCtxPopCurrent(&dummy);
return 0;
}
int nvenc_frame(const uint8_t *data, unsigned pts, uint8_t *out, uint32_t &outlen) {
NVENCSTATUS err;
NV_ENC_PIC_PARAMS params;
memset(&params, 0, sizeof(NV_ENC_PIC_PARAMS));
params.version = NV_ENC_PIC_PARAMS_VER;
params.encodePicFlags = NV_ENC_PIC_FLAG_FORCEINTRA | NV_ENC_PIC_FLAG_OUTPUT_SPSPPS;
nvenc.cuda_dl->cuCtxPushCurrent(nvenc.cu_ctx);
NV_ENC_LOCK_INPUT_BUFFER lockBufferParams;
memset(&lockBufferParams, 0, sizeof(NV_ENC_LOCK_INPUT_BUFFER));
lockBufferParams.version = NV_ENC_LOCK_INPUT_BUFFER_VER;
lockBufferParams.inputBuffer = nvenc.surf[nvenc.cursurf].input_surface;
err = nvenc.nvenc_funcs.nvEncLockInputBuffer(nvenc.nvenc_ctx, &lockBufferParams);
if (err != NV_ENC_SUCCESS)
return -1;
nvenc.surf[nvenc.cursurf].pitch = lockBufferParams.pitch;
//vlog.info("pitch %u", lockBufferParams.pitch);
// copy frame
unsigned y;
uint8_t *dst = (uint8_t *) lockBufferParams.bufferDataPtr;
const unsigned linelen = nvenc.surf[nvenc.cursurf].width * 4;
for (y = 0; y < (unsigned) nvenc.surf[nvenc.cursurf].height; y++) {
memcpy(dst, data, linelen);
data += linelen;
dst += lockBufferParams.pitch;
}
err = nvenc.nvenc_funcs.nvEncUnlockInputBuffer(nvenc.nvenc_ctx,
nvenc.surf[nvenc.cursurf].input_surface);
if (err != NV_ENC_SUCCESS)
return -1;
CUcontext dummy;
nvenc.cuda_dl->cuCtxPopCurrent(&dummy);
params.inputBuffer = nvenc.surf[nvenc.cursurf].input_surface;
params.bufferFmt = nvenc.surf[nvenc.cursurf].format;
params.inputWidth = nvenc.surf[nvenc.cursurf].width;
params.inputHeight = nvenc.surf[nvenc.cursurf].height;
params.inputPitch = nvenc.surf[nvenc.cursurf].pitch;
params.outputBitstream = nvenc.surf[nvenc.cursurf].output_surface;
params.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
params.inputTimeStamp = pts;
nvenc.cuda_dl->cuCtxPushCurrent(nvenc.cu_ctx);
err = nvenc.nvenc_funcs.nvEncEncodePicture(nvenc.nvenc_ctx, &params);
nvenc.cuda_dl->cuCtxPopCurrent(&dummy);
if (err != NV_ENC_SUCCESS)
return -1;
nvenc.cuda_dl->cuCtxPushCurrent(nvenc.cu_ctx);
// Get output
NV_ENC_LOCK_BITSTREAM lock_params;
memset(&lock_params, 0, sizeof(NV_ENC_LOCK_BITSTREAM));
lock_params.version = NV_ENC_LOCK_BITSTREAM_VER;
lock_params.doNotWait = 0;
lock_params.outputBitstream = nvenc.surf[nvenc.cursurf].output_surface;
// lock_params.sliceOffsets = slice_offsets; TODO?
err = nvenc.nvenc_funcs.nvEncLockBitstream(nvenc.nvenc_ctx, &lock_params);
if (err != NV_ENC_SUCCESS)
return -1;
memcpy(out, lock_params.bitstreamBufferPtr, lock_params.bitstreamSizeInBytes);
outlen = lock_params.bitstreamSizeInBytes;
err = nvenc.nvenc_funcs.nvEncUnlockBitstream(nvenc.nvenc_ctx,
nvenc.surf[nvenc.cursurf].output_surface);
if (err != NV_ENC_SUCCESS)
return -1;
nvenc.cuda_dl->cuCtxPopCurrent(&dummy);
//vlog.info("Pic type %x, idr %x i %x", lock_params.pictureType, NV_ENC_PIC_TYPE_IDR,
// NV_ENC_PIC_TYPE_I);
return 0;
}
void nvidia_unload() {
NV_ENC_PIC_PARAMS params;
memset(&params, 0, sizeof(NV_ENC_PIC_PARAMS));
params.version = NV_ENC_PIC_PARAMS_VER;
params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
nvenc.cuda_dl->cuCtxPushCurrent(nvenc.cu_ctx);
nvenc.nvenc_funcs.nvEncEncodePicture(nvenc.nvenc_ctx, &params);
int i;
for (i = 0; i < NUM_SURF; i++) {
nvenc.nvenc_funcs.nvEncDestroyInputBuffer(nvenc.nvenc_ctx,
nvenc.surf[i].input_surface);
nvenc.nvenc_funcs.nvEncDestroyBitstreamBuffer(nvenc.nvenc_ctx,
nvenc.surf[i].output_surface);
}
nvenc.nvenc_funcs.nvEncDestroyEncoder(nvenc.nvenc_ctx);
CUcontext dummy;
nvenc.cuda_dl->cuCtxPopCurrent(&dummy);
nvenc.cuda_dl->cuCtxDestroy(nvenc.cu_ctx);
nvenc_free_functions(&nvenc.nvenc_dl);
cuda_free_functions(&nvenc.cuda_dl);
}
/*
int main() {
unsigned w = 256, h = 256, kbps = 400, fps = 15;
memset(&nvenc, 0, sizeof(NvencDynLoadFunctions));
if (loadfuncs() < 0)
return 1;
if (setupdevice() < 0)
return 1;
if (setupenc(w, h, kbps, fps) < 0)
return 1;
if (setupsurf(w, h) < 0)
return 1;
unload();
return 0;
}
*/
int nvidia_init(const unsigned w, const unsigned h, const unsigned kbps,
const unsigned fps) {
memset(&nvenc, 0, sizeof(NvencDynLoadFunctions));
if (loadfuncs() < 0)
return 1;
if (setupdevice() < 0)
return 1;
if (setupenc(w, h, kbps, fps) < 0)
return 1;
if (setupsurf(w, h) < 0)
return 1;
return 0;
}

@ -0,0 +1,11 @@
#ifndef KASM_NVIDIA_H
#define KASM_NVIDIA_H
#include <stdint.h>
int nvidia_init(const unsigned w, const unsigned h, const unsigned kbps,
const unsigned fps);
int nvenc_frame(const uint8_t *data, unsigned pts, uint8_t *out, uint32_t &outlen);
void nvidia_unload();
#endif

5
debian/control vendored

@ -3,7 +3,8 @@ Section: x11
Priority: optional Priority: optional
Maintainer: Kasm Technologies LLC <info@kasmweb.com> Maintainer: Kasm Technologies LLC <info@kasmweb.com>
Build-Depends: debhelper (>= 11), rsync, libjpeg-dev, libjpeg-dev, libpng-dev, Build-Depends: debhelper (>= 11), rsync, libjpeg-dev, libjpeg-dev, libpng-dev,
libtiff-dev, libgif-dev, libavcodec-dev, libssl-dev, libgl1, libxfont2, libsm6 libtiff-dev, libgif-dev, libavcodec-dev, libssl-dev, libgl1, libxfont2, libsm6,
libx264-dev
Standards-Version: 4.1.3 Standards-Version: 4.1.3
Homepage: https://github.com/kasmtech/KasmVNC Homepage: https://github.com/kasmtech/KasmVNC
#Vcs-Browser: https://salsa.debian.org/debian/kasmvnc #Vcs-Browser: https://salsa.debian.org/debian/kasmvnc
@ -12,7 +13,7 @@ Homepage: https://github.com/kasmtech/KasmVNC
Package: kasmvncserver Package: kasmvncserver
Architecture: amd64 Architecture: amd64
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, ssl-cert, xauth, Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, ssl-cert, xauth,
x11-xkb-utils, xkb-data, procps x11-xkb-utils, xkb-data, procps, x264
Provides: vnc-server Provides: vnc-server
Description: VNC server accessible from a web browser Description: VNC server accessible from a web browser
VNC stands for Virtual Network Computing. It is, in essence, a remote VNC stands for Virtual Network Computing. It is, in essence, a remote

@ -1 +1 @@
Subproject commit 67466077c07377178599315b0cba01440ce6fb53 Subproject commit cd7a460920aa2a958023222d148f29ace77ebe2c

@ -46,7 +46,7 @@ Xvnc_CPPFLAGS = $(XVNC_CPPFLAGS) -DKASMVNC -DNO_MODULE_EXTS \
-I$(top_srcdir)/include ${XSERVERLIBS_CFLAGS} -I$(includedir) -I$(top_srcdir)/include ${XSERVERLIBS_CFLAGS} -I$(includedir)
Xvnc_LDADD = $(XVNC_LIBS) libvnccommon.la $(COMMON_LIBS) \ Xvnc_LDADD = $(XVNC_LIBS) libvnccommon.la $(COMMON_LIBS) \
$(XSERVER_LIBS) $(XSERVER_SYS_LIBS) $(XVNC_SYS_LIBS) -lX11 -lwebp -lssl -lcrypto -lcrypt $(XSERVER_LIBS) $(XSERVER_SYS_LIBS) $(XVNC_SYS_LIBS) -lX11 -lwebp -lssl -lcrypto -lcrypt -lx264
Xvnc_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG) -fopenmp Xvnc_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG) -fopenmp

@ -74,7 +74,7 @@ XserverDesktop::XserverDesktop(int screenIndex_,
: screenIndex(screenIndex_), : screenIndex(screenIndex_),
server(0), listeners(listeners_), server(0), listeners(listeners_),
directFbptr(true), directFbptr(true),
queryConnectId(0), queryConnectTimer(this) queryConnectId(0), queryConnectTimer(this), resizing(false)
{ {
format = pf; format = pf;
@ -251,7 +251,7 @@ void XserverDesktop::setCursor(int width, int height, int hotX, int hotY,
} }
try { try {
server->setCursor(width, height, Point(hotX, hotY), cursorData); server->setCursor(width, height, Point(hotX, hotY), cursorData, resizing);
} catch (rdr::Exception& e) { } catch (rdr::Exception& e) {
vlog.error("XserverDesktop::setCursor: %s",e.str()); vlog.error("XserverDesktop::setCursor: %s",e.str());
} }
@ -462,8 +462,11 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
layout.print(buffer, sizeof(buffer)); layout.print(buffer, sizeof(buffer));
vlog.debug("%s", buffer); vlog.debug("%s", buffer);
resizing = true;
vncSetGlueContext(screenIndex); vncSetGlueContext(screenIndex);
return ::setScreenLayout(fb_width, fb_height, layout, &outputIdMap); const unsigned int ret = ::setScreenLayout(fb_width, fb_height, layout, &outputIdMap);
resizing = false;
return ret;
} }
void XserverDesktop::handleClipboardRequest() void XserverDesktop::handleClipboardRequest()

@ -132,5 +132,7 @@ private:
OutputIdMap outputIdMap; OutputIdMap outputIdMap;
rfb::Point oldCursorPos; rfb::Point oldCursorPos;
bool resizing;
}; };
#endif #endif

@ -256,6 +256,10 @@ Scaling method to use when in downscaled video mode. 0 = nearest, 1 = bilinear,
Default \fB2\fP. Default \fB2\fP.
. .
.TP .TP
.B \-x264Bitrate \fInum\fP
Enable x264 encoding for full-screen video, in kbps. Default \fB0\fP (off).
.
.TP
.B \-CompareFB \fImode\fP .B \-CompareFB \fImode\fP
Perform pixel comparison on framebuffer to reduce unnecessary updates. Can Perform pixel comparison on framebuffer to reduce unnecessary updates. Can
be either \fB0\fP (off), \fB1\fP (always) or \fB2\fP (auto). Default is be either \fB0\fP (off), \fB1\fP (always) or \fB2\fP (auto). Default is

Loading…
Cancel
Save