<div dir="ltr">Thank you Francois and Thomas,<div>I've revised my code based on your feedback and re-emailed it. In the future I will bear in mind that the imperative form is preferred.</div><div><br></div><div>May I ask, what is the process of getting code accepted? Will there be a vote?</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Jun 28, 2019 at 5:59 PM Thomas Guillem <<a href="mailto:thomas@gllm.fr">thomas@gllm.fr</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hello,<br>
<br>
Nitpicking: "Added FBS demux" -> "Add FBS demux"<br>
We prefer the imperative form.<br>
<br>
On Fri, Jun 28, 2019, at 01:14, <a href="mailto:bkurniawan@orecx.com" target="_blank">bkurniawan@orecx.com</a> wrote:<br>
> From: budi-kurniawan <<a href="mailto:budi2020@gmail.com" target="_blank">budi2020@gmail.com</a>><br>
> <br>
> ---<br>
> modules/demux/Makefile.am | 7 +<br>
> modules/demux/fbs.cpp | 522 ++++++++++++++++++++++++++++++++++++<br>
> share/vlc.desktop.mimetypes | 1 +<br>
> src/input/demux.c | 1 +<br>
> src/misc/mime.c | 1 +<br>
> 5 files changed, 532 insertions(+)<br>
> create mode 100644 modules/demux/fbs.cpp<br>
> <br>
> diff --git a/modules/demux/Makefile.am b/modules/demux/Makefile.am<br>
> index 0251da6879..4c13a815f9 100644<br>
> --- a/modules/demux/Makefile.am<br>
> +++ b/modules/demux/Makefile.am<br>
> @@ -134,6 +134,13 @@ libavi_plugin_la_SOURCES = demux/avi/avi.c <br>
> demux/avi/libavi.c demux/avi/libavi.h<br>
> demux/avi/bitmapinfoheader.h<br>
> demux_LTLIBRARIES += <a href="http://libavi_plugin.la" rel="noreferrer" target="_blank">libavi_plugin.la</a><br>
> <br>
> +libfbs_plugin_la_SOURCES = demux/fbs.cpp<br>
> +libfbs_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(demuxdir)'<br>
> +libfbs_plugin_la_LIBADD = $(LIBS_fbs)<br>
> +libfbs_plugin_la_LIBADD += -lz<br>
> +demux_LTLIBRARIES += <a href="http://libfbs_plugin.la" rel="noreferrer" target="_blank">libfbs_plugin.la</a><br>
> +demux_LTLIBRARIES += $(LTLIBfbs)<br>
> +<br>
> libcaf_plugin_la_SOURCES = demux/caf.c<br>
> libcaf_plugin_la_LIBADD = $(LIBM)<br>
> demux_LTLIBRARIES += <a href="http://libcaf_plugin.la" rel="noreferrer" target="_blank">libcaf_plugin.la</a><br>
> diff --git a/modules/demux/fbs.cpp b/modules/demux/fbs.cpp<br>
> new file mode 100644<br>
> index 0000000000..27594e2601<br>
> --- /dev/null<br>
> +++ b/modules/demux/fbs.cpp<br>
> @@ -0,0 +1,522 @@<br>
> +/*****************************************************************************<br>
> + * fbs.cpp : fbs demuxer<br>
> + <br>
> *****************************************************************************<br>
> + * Copyright (C) 2019 OrecX LLC<br>
> + *<br>
> + * Author: Budi Kurniawan <<a href="mailto:bkurniawan@orecx.com" target="_blank">bkurniawan@orecx.com</a>><br>
> + *<br>
> + * This program is free software; you can redistribute it and/or <br>
> modify it<br>
> + * under the terms of the GNU Lesser General Public License as <br>
> published by<br>
> + * the Free Software Foundation; either version 2.1 of the License, or<br>
> + * (at your option) any later version.<br>
> + *<br>
> + * This program is distributed in the hope that it will be useful,<br>
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>
> + * GNU Lesser General Public License for more details.<br>
> + *<br>
> + * You should have received a copy of the GNU Lesser General Public <br>
> License<br>
> + * along with this program; if not, write to the Free Software <br>
> Foundation,<br>
> + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.<br>
> + <br>
> *****************************************************************************/<br>
> +#ifdef HAVE_CONFIG_H<br>
> +# include "config.h"<br>
> +#endif<br>
> +#include <assert.h><br>
> +#include <memory><br>
> +#include <vlc_common.h><br>
> +#include <vlc_demux.h><br>
> +#include <vlc_plugin.h><br>
> +#include "zlib.h"<br>
> +<br>
> +#define MAX_INFLATE_SIZE_ZLIB 128000<br>
> +/** Initial memory alignment of data block.<br>
> + * @note This must be a multiple of sizeof(void*) and a power of two.<br>
> + * libavcodec AVX optimizations require at least 32-bytes. */<br>
> +#define BLOCK_ALIGN 32<br>
> +<br>
> +/** Initial reserved header and footer size. */<br>
> +#define BLOCK_PADDING 32<br>
> +/*****************************************************************************<br>
> + * Module descriptor<br>
> + <br>
> *****************************************************************************/<br>
> +static int Open(vlc_object_t *);<br>
> +static void Close(vlc_object_t *);<br>
> +static int Seek(demux_t *, vlc_tick_t);<br>
> +static int Demux(demux_t *);<br>
> +static int Control(demux_t *, int, va_list);<br>
> +<br>
> +vlc_module_begin ()<br>
> + set_shortname( "FBS" )<br>
> + set_description( N_("FBS stream demuxer" ) )<br>
> + set_capability( "demux", 212 )<br>
> + set_callbacks( Open, Close )<br>
> + set_category( CAT_INPUT )<br>
> + set_subcategory( SUBCAT_INPUT_DEMUX )<br>
> +vlc_module_end ()<br>
> +<br>
> +/*****************************************************************************<br>
> + * Definitions of structures used by this plugin<br>
> + <br>
> *****************************************************************************/<br>
> +typedef struct {<br>
> + uint8_t bitsPerPixel;<br>
> + uint8_t depth;<br>
> + uint8_t bigEndianFlag;<br>
> + uint8_t trueColorFlag;<br>
> + uint16_t redMax;<br>
> + uint16_t greenMax;<br>
> + uint16_t blueMax;<br>
> + uint8_t redShift;<br>
> + uint8_t greenShift;<br>
> + uint8_t blueShift;<br>
> +} FbsPixelFormat;<br>
> +<br>
> +typedef struct {<br>
> + uint64_t frameSize;<br>
> + es_out_id_t *p_es_video;<br>
> + es_format_t fmt_video;<br>
> + date_t pcr;<br>
> + uint8_t rfbVersion;<br>
> + uint16_t frameBufferWidth;<br>
> + uint16_t frameBufferHeight;<br>
> + uint8_t framesPerSecond;<br>
> + uint16_t headerPos;<br>
> + vlc_tick_t timestamp;<br>
> + vlc_tick_t lastTimestamp;<br>
> + bool seeking;<br>
> + FbsPixelFormat fbsPixelFormat;<br>
> + uint64_t inflated;<br>
> + z_stream zStream;<br>
> + uint8_t zrleTilePixels24[3 * 64 * 64]; // A tile of 64 x 64 <br>
> pixels, 3 bytes per pixel<br>
> +} demux_sys_t;<br>
> +<br>
> +void copyTileToCanvas(const demux_sys_t *p_sys, const uint8_t <br>
> bitsPerPixel, const uint16_t frameBufferWidth,<br>
> + const uint32_t x, const uint32_t y, const uint8_t tileWidth, <br>
> const uint8_t tileHeight,<br>
> + uint8_t *canvas) {<br>
> + assert(tileWidth <= 64 && tileHeight <= 64);<br>
> + if (bitsPerPixel == 32) {<br>
> + for (uint8_t i = 0; i < tileHeight; i++) {<br>
> + for (uint8_t j = 0; j < tileWidth; j++) {<br>
> + int source = 3 * (i * tileWidth + j);<br>
> + int position = ((y + i) * frameBufferWidth + (x + j)) <br>
> * 3;<br>
> + canvas[position + 2] = <br>
> p_sys->zrleTilePixels24[source]; //red;<br>
> + canvas[position + 1] = p_sys->zrleTilePixels24[source <br>
> + 1]; //green;<br>
> + canvas[position] = p_sys->zrleTilePixels24[source + <br>
> 2]; //blue;<br>
> + }<br>
> + }<br>
> + }<br>
> +}<br>
> +<br>
> +uint32_t readPixel(const uint8_t bitsPerPixel, const uint8_t* data, <br>
> uint64_t* pos) {<br>
> + uint32_t pixel = 0;<br>
> + if (bitsPerPixel == 32) {<br>
> + uint8_t red = data[(*pos)++];<br>
> + uint8_t green = data[(*pos)++];<br>
> + uint8_t blue = data[(*pos)++];<br>
> + pixel = red << 16 | green << 8 | blue;<br>
> + }<br>
> + return pixel;<br>
> +}<br>
> +<br>
> +ssize_t inf(demux_sys_t *p_sys, const uint8_t* input, const uint64_t <br>
> inputLength, uint8_t *buf) {<br>
> + p_sys->zStream.avail_in = inputLength;<br>
> + p_sys->zStream.next_in = (uint8_t*) input;<br>
> + uint8_t chunkData[MAX_INFLATE_SIZE_ZLIB];<br>
> + uint32_t count = 0;<br>
> + while(1) {<br>
> + p_sys->zStream.avail_out = MAX_INFLATE_SIZE_ZLIB;<br>
> + p_sys->zStream.next_out = chunkData;<br>
> + int inflateResult = inflate(&p_sys->zStream, Z_NO_FLUSH);<br>
> + uint32_t numBytesLeft = p_sys->zStream.total_out - <br>
> p_sys->inflated;<br>
> + for (unsigned int i = 0; i < numBytesLeft; i++) {<br>
> + buf[count++] = chunkData[i];<br>
> + }<br>
> + p_sys->inflated = p_sys->zStream.total_out;<br>
> + if (inflateResult != Z_OK || p_sys->zStream.avail_in == 0<br>
> + || (p_sys->zStream.avail_out != 0 && inflateResult == <br>
> Z_STREAM_END)) {<br>
> + break;<br>
> + }<br>
> + }<br>
> + return count;<br>
> +}<br>
> +<br>
> +void populateColorArray(const uint8_t bitsPerPixel, const uint8_t* <br>
> rectData, uint64_t* pos,<br>
> + uint8_t colorArray[], const uint16_t paletteSize) {<br>
> + assert(paletteSize <= 64 * 64);<br>
> + if (bitsPerPixel == 32) {<br>
> + for (uint16_t i = 0; i < paletteSize; i++) {<br>
> + uint16_t index = i * 3;<br>
> + colorArray[index++] = rectData[(*pos)++]; // red<br>
> + colorArray[index++] = rectData[(*pos)++]; // green<br>
> + colorArray[index] = rectData[(*pos)++]; // blue<br>
> + }<br>
> + }<br>
> +}<br>
> +<br>
> +void handlePackedPixels(uint8_t *zrleTilePixels24, const uint8_t* <br>
> data, uint64_t* pos, const uint8_t tileWidth,<br>
> + const uint8_t tileHeight, const uint8_t colorArray[], const <br>
> uint16_t paletteSize) {<br>
> + assert(tileWidth <= 64 && tileHeight <= 64);<br>
> + uint8_t shift = 1;<br>
> + if (paletteSize > 16) {<br>
> + shift = 8;<br>
> + } else if (paletteSize > 4) {<br>
> + shift = 4;<br>
> + } else if (paletteSize > 2) {<br>
> + shift = 2;<br>
> + }<br>
> + uint16_t index = 0;<br>
> + for (uint8_t i = 0; i < tileHeight; ++i) {<br>
> + uint16_t end = index + tileWidth;<br>
> + uint8_t counter1;<br>
> + uint16_t counter2 = 0;<br>
> + while (index < end) {<br>
> + if (counter2 == 0) {<br>
> + counter1 = data[(*pos)++];<br>
> + counter2 = 8;<br>
> + }<br>
> + counter2 -= shift;<br>
> + uint16_t colorIndex = 3 * ((counter1 >> counter2) & ((1 << <br>
> shift) - 1));<br>
> + zrleTilePixels24[index * 3] = colorArray[colorIndex++];<br>
> + zrleTilePixels24[index * 3 + 1] = colorArray[colorIndex++];<br>
> + zrleTilePixels24[index * 3 + 2] = colorArray[colorIndex];<br>
> + index++;<br>
> + }<br>
> + }<br>
> +}<br>
> +<br>
> +void handlePackedRLEPixels(uint8_t *zrleTilePixels24, const uint8_t* <br>
> data, uint64_t* pos,<br>
> + const uint8_t tileWidth, const uint8_t tileHeight, const <br>
> uint8_t colorArray[]) {<br>
> + assert(tileWidth <= 64 && tileHeight <= 64);<br>
> + uint16_t index = 0;<br>
> + uint16_t end = tileWidth * tileHeight;<br>
> + while (index < end) {<br>
> + uint8_t flag = data[(*pos)++];<br>
> + uint16_t totalLength = 1;<br>
> + if ((flag & 128) != 0) {<br>
> + uint8_t length;<br>
> + do {<br>
> + length = data[(*pos)++];<br>
> + totalLength += length;<br>
> + } while (length == 255);<br>
> + assert(totalLength <= end - index);<br>
> + }<br>
> + flag &= 127;<br>
> + while (totalLength-- != 0) {<br>
> + zrleTilePixels24[3 * index] = colorArray[3 * flag];<br>
> + zrleTilePixels24[3 * index + 1] = colorArray[3 * flag + 1];<br>
> + zrleTilePixels24[3 * index + 2] = colorArray[3 * flag + 2];<br>
> + index++;<br>
> + }<br>
> + }<br>
> +}<br>
> +<br>
> +void handlePlainRLEPixels(uint8_t *zrleTilePixels24, const uint8_t <br>
> bitsPerPixel,<br>
> + const uint8_t* data, uint64_t* pos, const uint8_t tileWidth, <br>
> const uint8_t tileHeight) {<br>
> + assert(tileWidth <= 64 && tileHeight <= 64);<br>
> + uint16_t index = 0;<br>
> + uint16_t end = tileWidth * tileHeight;<br>
> + while (index < end) {<br>
> + uint8_t length;<br>
> + uint32_t pixel = readPixel(bitsPerPixel, data, pos);<br>
> + uint16_t totalLength = 1;<br>
> + do {<br>
> + length = data[(*pos)++];<br>
> + totalLength += length;<br>
> + } while (length == 255);<br>
> + assert(totalLength <= end - index);<br>
> + while (totalLength-- > 0) {<br>
> + zrleTilePixels24[3 * index] = (pixel & 0xFF0000) >> 16;<br>
> + zrleTilePixels24[3 * index + 1] = (pixel & 0xFF00) >> 8;<br>
> + zrleTilePixels24[3 * index + 2] = pixel & 0xFF;<br>
> + index++;<br>
> + }<br>
> + }<br>
> +}<br>
> +<br>
> +void handleFrame(demux_sys_t *p_sys, const uint8_t bitsPerPixel,<br>
> + const uint16_t frameBufferWidth, const uint8_t *data, uint8_t <br>
> *canvas) {<br>
> + // byte 1 = message type, byte 2 = padding, both can be ignored<br>
> + uint16_t rectCount = U16_AT(&data[2]);<br>
> + uint64_t pos = 4;<br>
> + for (uint16_t i = 0; i < rectCount; i++) {<br>
> + uint16_t rectX = U16_AT(&data[pos]);<br>
> + pos += 2;<br>
> + uint16_t rectY = U16_AT(&data[pos]);<br>
> + pos += 2;<br>
> + uint16_t rectWidth = U16_AT(&data[pos]);<br>
> + pos += 2;<br>
> + uint16_t rectHeight = U16_AT(&data[pos]);<br>
> + pos += 2;<br>
> + pos += 4; // skip encoding<br>
> + const uint32_t rectDataLength = U32_AT(&data[pos]);<br>
> + pos += 4;<br>
> +<br>
> + uint8_t* inflatedData = new uint8_t[10 * <br>
> MAX_INFLATE_SIZE_ZLIB];<br>
> + if (!inflatedData) {<br>
> + return;<br>
> + }<br>
> + inf(p_sys, data + pos, rectDataLength, inflatedData);<br>
> +<br>
> + pos += rectDataLength;<br>
> + uint64_t inflatedDataReadPosition = 0;<br>
> + for (int j = rectY; j < rectY + rectHeight; j += 64) {<br>
> + // last row tiles may have height that is < 64<br>
> + int tileHeight = std::min(64, rectY + rectHeight - j);<br>
> + for (int k = rectX; k < rectX + rectWidth; k += 64) {<br>
> + // last column tiles may have width that is < 64<br>
> + int tileWidth = std::min(64, rectX + rectWidth - k);<br>
> + uint8_t subencoding = <br>
> inflatedData[inflatedDataReadPosition++];<br>
> + bool runLength = (subencoding & 0x80) != 0;<br>
> + uint8_t paletteSize = subencoding & 0x7F;<br>
> + uint8_t colorArray[128 * 3];<br>
> + populateColorArray(bitsPerPixel, inflatedData,<br>
> + &inflatedDataReadPosition, colorArray, <br>
> paletteSize);<br>
> + // read palette colors<br>
> + if (paletteSize == 1) {<br>
> + for (uint16_t d = j; d < j + tileHeight; d++) {<br>
> + for (uint16_t e = k; e < k + tileWidth; e++) {<br>
> + uint32_t index = (d * frameBufferWidth + <br>
> e) * 3;<br>
> + canvas[index++] = colorArray[0]; //red;<br>
> + canvas[index++] = colorArray[1]; //green;<br>
> + canvas[index] = colorArray[2]; //blue;<br>
> + }<br>
> + }<br>
> + continue;<br>
> + }<br>
> + if (!runLength) {<br>
> + if (paletteSize == 0) {<br>
> + populateColorArray(bitsPerPixel, inflatedData, <br>
> &inflatedDataReadPosition,<br>
> + p_sys->zrleTilePixels24, tileWidth * <br>
> tileHeight);<br>
> + } else {<br>
> + handlePackedPixels(p_sys->zrleTilePixels24, <br>
> inflatedData, &inflatedDataReadPosition,<br>
> + tileWidth, tileHeight, colorArray, <br>
> paletteSize);<br>
> + }<br>
> + } else {<br>
> + if (paletteSize == 0) {<br>
> + handlePlainRLEPixels(p_sys->zrleTilePixels24, <br>
> bitsPerPixel, inflatedData,<br>
> + &inflatedDataReadPosition, tileWidth, <br>
> tileHeight);<br>
> + } else {<br>
> + handlePackedRLEPixels(p_sys->zrleTilePixels24, <br>
> inflatedData, &inflatedDataReadPosition, tileWidth,<br>
> + tileHeight, colorArray);<br>
> + }<br>
> + }<br>
> + copyTileToCanvas(p_sys, bitsPerPixel, <br>
> frameBufferWidth, k, j, tileWidth, tileHeight, canvas);<br>
> + }<br>
> + }<br>
> + delete[] inflatedData;<br>
> + }<br>
> +}<br>
> +uint32_t readLastTimestamp(stream_t *s) {<br>
> + // The last 4 bytes of the stream contains the last timestamp.<br>
> + // We read the last 4 bytes by repeatedly calling vlc_stream_Read <br>
> until EOF is reached<br>
> + const uint16_t len = 10000;<br>
> + uint8_t buf[len];<br>
> + uint8_t ts[4];<br>
> + while(!vlc_stream_Eof(s)) {<br>
> + const uint16_t bytesRead = vlc_stream_Read(s, buf, len);<br>
> + if (bytesRead >= 4) {<br>
> + for (int i = 0; i < 4; i++) {<br>
> + ts[i] = buf[bytesRead - 4 + i];<br>
> + }<br>
> + } else {<br>
> + //shift<br>
> + if (bytesRead != 0) {<br>
> + for (int i = 0; i < 4 - bytesRead; i++) {<br>
> + ts[i] = ts[i + bytesRead];<br>
> + }<br>
> + // copy bytesRead<br>
> + for (int i = 0; i < bytesRead; i++) {<br>
> + ts[i + 4 - bytesRead] = buf[i];<br>
> + }<br>
> + }<br>
> + }<br>
> + }<br>
> + return U32_AT(&ts);<br>
> +}<br>
> +<br>
> +void resetZStream(demux_sys_t *p_sys) {<br>
> + p_sys->inflated = p_sys->zStream.avail_in = 0;<br>
> + p_sys->zStream.zalloc = Z_NULL;<br>
> + p_sys->zStream.zfree = Z_NULL;<br>
> + p_sys->zStream.opaque = Z_NULL;<br>
> + p_sys->zStream.next_in = Z_NULL;<br>
> + inflateInit(&p_sys->zStream);<br>
> +}<br>
> +<br>
> +void updateCanvas(const demux_t *p_demux, const uint8_t bitsPerPixel,<br>
> + const uint16_t frameBufferWidth, const uint64_t frameSize, <br>
> const uint32_t t) {<br>
> + demux_sys_t *p_sys = (demux_sys_t *) p_demux->p_sys;<br>
> + block_t *p_block = block_Alloc(p_sys->frameSize);<br>
> + p_block->i_buffer = p_sys->frameSize;<br>
> + while (p_sys->timestamp <= t) {<br>
> + uint8_t buf[4];<br>
> + if (vlc_stream_Read(p_demux->s, buf, 4) < 4) {<br>
> + return;<br>
> + }<br>
> + uint32_t dataLength = U32_AT(&buf);<br>
> + uint32_t paddedDataLength = 4 * ((dataLength + 3) / 4);<br>
> + block_t *frameData = vlc_stream_Block(p_demux->s, <br>
> paddedDataLength + /*timestamp*/4);<br>
> + frameData->i_size = frameSize + BLOCK_ALIGN + 2 * <br>
> BLOCK_PADDING;<br>
> + frameData->i_buffer = frameSize;<br>
> + p_sys->timestamp = <br>
> U32_AT(&frameData->p_buffer[paddedDataLength]);<br>
> + handleFrame(p_sys, bitsPerPixel, frameBufferWidth, <br>
> frameData->p_buffer, p_block->p_buffer);<br>
> + block_Release(frameData);<br>
> + }<br>
> + p_block->i_dts = p_block->i_pts = p_sys->timestamp * 1000;<br>
> + es_out_Send(p_demux->out, p_sys->p_es_video, p_block);<br>
> +}<br>
> +<br>
> +/*****************************************************************************<br>
> + * Open: initializes FBS demux structures<br>
> + <br>
> *****************************************************************************/<br>
> +static int Open(vlc_object_t *p_this) {<br>
> + demux_t *p_demux = (demux_t*) p_this;<br>
> + demux_sys_t *p_sys;<br>
> + p_demux->p_sys = p_sys = (demux_sys_t*) <br>
> malloc(sizeof(demux_sys_t));<br>
> + const vlc_fourcc_t i_chroma = VLC_CODEC_RGB24;<br>
> + const uint8_t i_sar_num = 1;<br>
> + const uint8_t i_sar_den = 1;<br>
> + const uint8_t *p_peek;<br>
> +<br>
> + p_sys->framesPerSecond = 5;<br>
> + p_sys->timestamp = 0;<br>
> + p_sys->seeking = false;<br>
> + int readBytes = vlc_stream_Peek(p_demux->s, &p_peek, 2000);<br>
Use a ssize_t.<br>
> + if (readBytes == -1) {<br>
<br>
you should check the return of vlc_stream_Peek() and only access data within its range.<br>
<br>
<br>
> + return VLC_EGENERIC;<br>
> + }<br>
> + if (memcmp((char*) p_peek, "FBS 001.000", 11)) {<br>
> + return VLC_EGENERIC; // file invalid<br>
> + }<br>
> +<br>
> + uint64_t pos = 12;<br>
> + for (uint8_t frameNo = 1; frameNo < 6; frameNo++) {<br>
> + uint32_t dataLength = U32_AT(&p_peek[pos]);<br>
> + uint32_t paddedDataLength = 4 * ((dataLength + 3) / 4);<br>
> + if (frameNo == 1) {<br>
> + p_sys->rfbVersion = p_peek[pos + 14] - 48; // rfbVersion <br>
> is either 3 or 8<br>
> + }<br>
> + if (frameNo == 3 && p_sys->rfbVersion == 3) {<br>
> + // no security result for RFB 3.3, skip<br>
> + continue;<br>
> + }<br>
> + if (frameNo == 4) {<br>
> + p_sys->frameBufferWidth = U16_AT(&p_peek[pos + 4]);<br>
> + p_sys->frameBufferHeight = U16_AT(&p_peek[pos + 6]);<br>
> + p_sys->fbsPixelFormat.bitsPerPixel = p_peek[pos + 8];<br>
> + p_sys->fbsPixelFormat.depth = p_peek[pos + 9];<br>
> + p_sys->fbsPixelFormat.bigEndianFlag = p_peek[pos + 10];<br>
> + p_sys->fbsPixelFormat.trueColorFlag = p_peek[pos + 11];<br>
> + p_sys->fbsPixelFormat.redMax = U16_AT(&p_peek[pos + 12]);<br>
> + p_sys->fbsPixelFormat.greenMax = U16_AT(&p_peek[pos + 14]);<br>
> + p_sys->fbsPixelFormat.blueMax = U16_AT(&p_peek[pos + 16]);<br>
> + p_sys->fbsPixelFormat.redShift = p_peek[pos + 18];<br>
> + p_sys->fbsPixelFormat.greenShift = p_peek[pos + 19];<br>
> + p_sys->fbsPixelFormat.blueShift = p_peek[pos + 20];<br>
> + }<br>
> + pos += 4 + paddedDataLength + /* timestamp */4;<br>
> + p_sys->headerPos = pos; // used by SEEK<br>
> + }<br>
> +<br>
> + /* Set the demux function */<br>
> + es_format_Init(&p_sys->fmt_video, VIDEO_ES, i_chroma);<br>
> + video_format_Setup(&p_sys->fmt_video.video, i_chroma,<br>
> + p_sys->frameBufferWidth, p_sys->frameBufferHeight,<br>
> + p_sys->frameBufferWidth, p_sys->frameBufferHeight,<br>
> + i_sar_num, i_sar_den);<br>
> +<br>
> + date_Init(&p_sys->pcr, p_sys->fmt_video.video.i_frame_rate,<br>
> + p_sys->fmt_video.video.i_frame_rate_base);<br>
> + date_Set(&p_sys->pcr, VLC_TICK_0);<br>
> +<br>
> + const vlc_chroma_description_t *dsc = <br>
> vlc_fourcc_GetChromaDescription(<br>
> + p_sys->fmt_video.video.i_chroma);<br>
> + p_sys->frameSize = p_sys->frameBufferWidth * <br>
> p_sys->frameBufferHeight * dsc->pixel_size; // dsc->pixel_size = 3<br>
> + p_sys->p_es_video = es_out_Add(p_demux->out, &p_sys->fmt_video);<br>
> + p_demux->pf_demux = Demux;<br>
> + p_demux->pf_control = Control;<br>
> + resetZStream(p_sys);<br>
> + // skip to position of data<br>
> + //readBytes = vlc_stream_Read(p_demux->s, NULL, 10*pos);<br>
> + p_sys->lastTimestamp = readLastTimestamp(p_demux->s);<br>
> + readBytes = vlc_stream_Seek(p_demux->s, pos);<br>
> + return VLC_SUCCESS;<br>
> +}<br>
> +<br>
> +/*****************************************************************************<br>
> + * Close: frees unused data<br>
> + <br>
> *****************************************************************************/<br>
> +static void Close(vlc_object_t *p_this) {<br>
> + demux_t *p_demux = (demux_t*) p_this;<br>
> + demux_sys_t *p_sys = (demux_sys_t*) p_demux->p_sys;<br>
> + free(p_sys);<br>
> +}<br>
> +<br>
> +/*****************************************************************************<br>
> + * Control:<br>
> + <br>
> *****************************************************************************/<br>
> +static int Control(demux_t *p_demux, int i_query, va_list args) {<br>
> + demux_sys_t *p_sys = (demux_sys_t*) p_demux->p_sys;<br>
> + const int64_t i_bps = 8LL * p_sys->frameSize;<br>
> + switch (i_query) {<br>
> + case DEMUX_GET_LENGTH:<br>
> + //assign a number in microseconds: timestamp (in ms) * 1000<br>
> + *va_arg(args, vlc_tick_t *) = p_sys->lastTimestamp * 1000;<br>
> + return VLC_SUCCESS;<br>
> + case DEMUX_CAN_SEEK:<br>
> + *va_arg(args, bool *) = true;<br>
> + return VLC_SUCCESS;<br>
> + case DEMUX_GET_TIME:<br>
> + *va_arg(args, vlc_tick_t *) = p_sys->timestamp * 1000;<br>
> + return VLC_SUCCESS;<br>
> + case DEMUX_GET_POSITION:<br>
> + double *pf;<br>
> + pf = va_arg(args, double *);<br>
> + *pf = (double) p_sys->timestamp / (double) <br>
> p_sys->lastTimestamp;<br>
> + return VLC_SUCCESS;<br>
> + case DEMUX_SET_POSITION:<br>
> + double f = va_arg(args, double);<br>
> + vlc_tick_t i64 = f * 1000;<br>
> + return Seek(p_demux, i64);<br>
> + }<br>
> + return demux_vaControlHelper(p_demux->s, 0, -1, i_bps,<br>
> + p_sys->frameSize, i_query, args);<br>
> +}<br>
> +<br>
> +/*****************************************************************************<br>
> + * Demux: reads and demuxes data packets<br>
> + <br>
> *****************************************************************************<br>
> + * Returns -1 in case of error, 0 in case of EOF, 1 otherwise<br>
> + <br>
> *****************************************************************************/<br>
> +static int Demux(demux_t *p_demux) {<br>
> + demux_sys_t *p_sys = (demux_sys_t *) p_demux->p_sys;<br>
> + vlc_tick_t pcr = date_Get(&p_sys->pcr);<br>
> + es_out_SetPCR(p_demux->out, pcr);<br>
> + if (!p_sys->seeking) {<br>
> + updateCanvas(p_demux, p_sys->fbsPixelFormat.bitsPerPixel,<br>
> + p_sys->frameBufferWidth, p_sys->frameSize, pcr / 1000);<br>
> + }<br>
> + p_sys->pcr.i_divider_num = p_sys->framesPerSecond; //how many <br>
> times in a second Demux() is called<br>
> + p_sys->pcr.i_divider_den = 1;<br>
> + date_Increment(&p_sys->pcr, 1);<br>
> + return VLC_DEMUXER_SUCCESS;<br>
> +}<br>
> +<br>
> +static int Seek(demux_t *p_demux, vlc_tick_t i_date) {<br>
> + demux_sys_t *p_sys = (demux_sys_t *) p_demux->p_sys;<br>
> + uint32_t soughtTimestamp = i_date * p_sys->lastTimestamp / 1000;<br>
> + // Rewind to right after the header<br>
> + if (vlc_stream_Seek(p_demux->s, p_sys->headerPos) == -1) {<br>
> + return VLC_DEMUXER_EOF;<br>
> + }<br>
> + p_sys->seeking = true;<br>
> + p_sys->pcr.i_divider_num = 0;<br>
> + resetZStream(p_sys);<br>
> +<br>
> + p_sys->timestamp = 0;<br>
> + updateCanvas(p_demux, p_sys->fbsPixelFormat.bitsPerPixel,<br>
> + p_sys->frameBufferWidth, p_sys->frameSize, <br>
> soughtTimestamp);<br>
> + p_sys->seeking = false;<br>
> + p_sys->pcr.date = soughtTimestamp * 1000;<br>
> + return VLC_SUCCESS;<br>
> +}<br>
> diff --git a/share/vlc.desktop.mimetypes b/share/vlc.desktop.mimetypes<br>
> index 0d866f7da8..88d1215bdd 100644<br>
> --- a/share/vlc.desktop.mimetypes<br>
> +++ b/share/vlc.desktop.mimetypes<br>
> @@ -42,6 +42,7 @@ video/msvideo<br>
> video/vnd.divx<br>
> video/avi<br>
> video/x-avi<br>
> +video/fbs<br>
> <br>
> # Real audio and video<br>
> application/vnd.rn-realmedia # RM<br>
> diff --git a/src/input/demux.c b/src/input/demux.c<br>
> index d7b5ce3711..7ebe58a8ef 100644<br>
> --- a/src/input/demux.c<br>
> +++ b/src/input/demux.c<br>
> @@ -88,6 +88,7 @@ static const char* DemuxNameFromExtension( char const* ext,<br>
> { "avi", "avi" },<br>
> { "drc", "dirac" },<br>
> { "dv", "dv" },<br>
> + { "fbs", "fbs" },<br>
> { "flac", "flac" },<br>
> { "h264", "h264" },<br>
> { "kar", "smf" },<br>
> diff --git a/src/misc/mime.c b/src/misc/mime.c<br>
> index 03a400662a..272ac67d1f 100644<br>
> --- a/src/misc/mime.c<br>
> +++ b/src/misc/mime.c<br>
> @@ -58,6 +58,7 @@ static const struct<br>
> /* media mime */<br>
> { ".avi", "video/avi" },<br>
> { ".asf", "video/x-ms-asf" },<br>
> + { ".fbs", "video/fbs" },<br>
> { ".m1a", "audio/mpeg" },<br>
> { ".m2a", "audio/mpeg" },<br>
> { ".m1v", "video/mpeg" },<br>
> -- <br>
> 2.17.1<br>
> <br>
> _______________________________________________<br>
> vlc-devel mailing list<br>
> To unsubscribe or modify your subscription options:<br>
> <a href="https://mailman.videolan.org/listinfo/vlc-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/vlc-devel</a><br>
_______________________________________________<br>
vlc-devel mailing list<br>
To unsubscribe or modify your subscription options:<br>
<a href="https://mailman.videolan.org/listinfo/vlc-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/vlc-devel</a></blockquote></div>