Skip to content
Open
851 changes: 851 additions & 0 deletions guacamole-common-js/src/main/webapp/modules/CameraRecorder.js

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions guacamole-common-js/src/main/webapp/modules/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,25 @@ Guacamole.Client = function(tunnel) {

};

/**
* Opens a new video stream for writing, having the given mimetype. The
* instruction necessary to create this stream will automatically be sent.
*
* @param {!string} mimetype
* The mimetype of the video data being sent.
*
* @return {!Guacamole.OutputStream}
* The created video stream.
*/
this.createVideoStream = function(mimetype) {

// Allocate and associate stream with video metadata
var stream = guac_client.createOutputStream();
tunnel.sendMessage("video", stream.index, mimetype);
return stream;

};

/**
* Opens a new file for writing, having the given index, mimetype and
* filename. The instruction necessary to create this stream will
Expand Down
100 changes: 100 additions & 0 deletions guacamole-common-js/src/main/webapp/modules/H264AnnexBUtil.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

var Guacamole = Guacamole || {};

/**
* Utilities for converting H.264 AVCC format to Annex-B.
*/
Guacamole.H264AnnexBUtil = (function() {

/**
* Converts an AVCC payload into Annex-B format. If isKey is true and the
* provided config contains SPS/PPS, those will be prepended using start
* codes. The config.lengthSize determines the size (in bytes) of the
* length prefixes for NAL units within the AVCC payload.
*
* @param {!Uint8Array} payload
* The AVCC payload containing one or more NAL units with length
* prefixes of size config.lengthSize.
*
* @param {!boolean} isKey
* Whether this payload corresponds to a keyframe (IDR).
*
* @param {{ lengthSize: number, sps: Uint8Array[], pps: Uint8Array[] }|null} config
* Decoder configuration including SPS/PPS and the AVCC lengthSize. If
* null, SPS/PPS will not be included and a default lengthSize of 4 is
* assumed.
*
* @returns {!Uint8Array}
* The Annex-B formatted byte sequence.
*/
function avccToAnnexB(payload, isKey, config) {
var startCode = new Uint8Array([0x00, 0x00, 0x00, 0x01]);
var outParts = [];

var haveConfig = !!config;
var lenSize = (haveConfig && config.lengthSize) ? config.lengthSize : 4;

if (isKey && haveConfig) {
for (var i = 0; i < (config.sps ? config.sps.length : 0); i++) {
outParts.push(startCode);
outParts.push(config.sps[i]);
}
for (var j = 0; j < (config.pps ? config.pps.length : 0); j++) {
outParts.push(startCode);
outParts.push(config.pps[j]);
}
}

var dv = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);
var off = 0;
while (off + lenSize <= dv.byteLength) {
var nalLen = 0;
for (var k = 0; k < lenSize; k++)
nalLen = (nalLen << 8) | dv.getUint8(off + k);
off += lenSize;
if (nalLen <= 0)
continue;
if (off + nalLen > dv.byteLength)
break;
var nal = new Uint8Array(payload.buffer, payload.byteOffset + off, nalLen);
outParts.push(startCode);
outParts.push(nal);
off += nalLen;
}

var total = 0;
for (var p = 0; p < outParts.length; p++) total += outParts[p].length;
var out = new Uint8Array(total);
var pos = 0;
for (var q = 0; q < outParts.length; q++) {
out.set(outParts[q], pos);
pos += outParts[q].length;
}

return out;
}

return {
avccToAnnexB: avccToAnnexB
};

})();

58 changes: 58 additions & 0 deletions guacamole-common-js/src/main/webapp/tests/H264AnnexBUtilSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

describe('Guacamole.H264AnnexBUtil', function() {

it('converts AVCC with lengthSize=1 to Annex-B', function() {
var payload = new Uint8Array([ 0x00, 0x01, 0x65 ]); // len=1, NAL=0x65
var config = { lengthSize: 1, sps: [], pps: [] };
var out = Guacamole.H264AnnexBUtil.avccToAnnexB(payload, false, config);
// 4-byte start code + 1-byte nal
expect(out.length).toBe(5);
expect(Array.prototype.slice.call(out)).toEqual([0,0,0,1,0x65]);
});

it('prepends SPS/PPS on keyframe', function() {
var payload = new Uint8Array([ 0x00, 0x01, 0x65 ]);
var sps = new Uint8Array([0x67, 0x64]);
var pps = new Uint8Array([0x68, 0xEE]);
var config = { lengthSize: 1, sps: [sps], pps: [pps] };
var out = Guacamole.H264AnnexBUtil.avccToAnnexB(payload, true, config);
// start+SPS + start+PPS + start+IDR
expect(Array.prototype.slice.call(out)).toEqual([
0,0,0,1,0x67,0x64,
0,0,0,1,0x68,0xEE,
0,0,0,1,0x65
]);
});

it('supports lengthSize=2 and 4', function() {
// lengthSize=2, nal len=2 -> [00 02 AA BB]
var payload2 = new Uint8Array([ 0x00,0x02, 0xAA,0xBB ]);
var out2 = Guacamole.H264AnnexBUtil.avccToAnnexB(payload2, false, { lengthSize: 2, sps: [], pps: [] });
expect(Array.prototype.slice.call(out2)).toEqual([0,0,0,1,0xAA,0xBB]);

// lengthSize=4, nal len=1 -> [00 00 00 01 CC]
var payload4 = new Uint8Array([ 0x00,0x00,0x00,0x01, 0xCC ]);
var out4 = Guacamole.H264AnnexBUtil.avccToAnnexB(payload4, false, { lengthSize: 4, sps: [], pps: [] });
expect(Array.prototype.slice.call(out4)).toEqual([0,0,0,1,0xCC]);
});
});


Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@
"type" : "BOOLEAN",
"options" : [ "true" ]
},
{
"name" : "enable-rdpecam",
"type" : "BOOLEAN",
"options" : [ "true" ]
},
{
"name" : "enable-printing",
"type" : "BOOLEAN",
Expand Down
Loading