Compare commits

...

17 Commits

2
.gitmodules vendored

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

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

@ -50,7 +50,7 @@ namespace rfb {
int w, int h,
const ScreenSet& layout);
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 setName(const char* name);
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);

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

@ -199,6 +199,10 @@ rfb::IntParameter rfb::Server::videoScaling
("VideoScaling",
"Scaling method to use when in downscaled video mode. 0 = nearest, 1 = bilinear, 2 = prog bilinear",
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
("PrintVideoArea",
"Print the detected video area % value.",

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

@ -24,7 +24,8 @@ namespace rfb {
const unsigned int tightJpeg = 0x09;
const unsigned int tightPng = 0x0a;
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
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
// non-premultiplied alpha.
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
// 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,
const rdr::U8* data)
const rdr::U8* data, const bool resizing)
{
delete cursor;
cursor = new Cursor(width, height, newHotspot, data);
@ -587,6 +587,13 @@ void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
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;
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
ci_next = ci; ci_next++;

@ -102,7 +102,7 @@ namespace rfb {
virtual void add_changed(const Region &region);
virtual void add_copied(const Region &dest, const Point &delta);
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 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
Maintainer: Kasm Technologies LLC <info@kasmweb.com>
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
Homepage: https://github.com/kasmtech/KasmVNC
#Vcs-Browser: https://salsa.debian.org/debian/kasmvnc
@ -12,7 +13,7 @@ Homepage: https://github.com/kasmtech/KasmVNC
Package: kasmvncserver
Architecture: amd64
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
Description: VNC server accessible from a web browser
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)
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

@ -74,7 +74,7 @@ XserverDesktop::XserverDesktop(int screenIndex_,
: screenIndex(screenIndex_),
server(0), listeners(listeners_),
directFbptr(true),
queryConnectId(0), queryConnectTimer(this)
queryConnectId(0), queryConnectTimer(this), resizing(false)
{
format = pf;
@ -251,7 +251,7 @@ void XserverDesktop::setCursor(int width, int height, int hotX, int hotY,
}
try {
server->setCursor(width, height, Point(hotX, hotY), cursorData);
server->setCursor(width, height, Point(hotX, hotY), cursorData, resizing);
} catch (rdr::Exception& e) {
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));
vlog.debug("%s", buffer);
resizing = true;
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()

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

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

Loading…
Cancel
Save