added differential frames encoding/decoding, and bandwidth items

This commit is contained in:
csoler 2015-08-10 22:13:50 -04:00
parent c0614e70ac
commit 3bda2c2660
5 changed files with 213 additions and 55 deletions

View File

@ -29,17 +29,14 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <QTimer>
//#include "AudioInput.h"
//#include "AudioOutput.h"
#include "AudioStats.h" #include "AudioStats.h"
#include "AudioInputConfig.h" #include "AudioInputConfig.h"
//#include "Global.h"
//#include "NetworkConfig.h"
#include "audiodevicehelper.h" #include "audiodevicehelper.h"
#include "AudioWizard.h" #include "AudioWizard.h"
#include "gui/common/RSGraphWidget.h" #include "gui/common/RSGraphWidget.h"
#include "util/RsProtectedTimer.h"
#include <interface/rsVOIP.h> #include <interface/rsVOIP.h>
#define iroundf(x) ( static_cast<int>(x) ) #define iroundf(x) ( static_cast<int>(x) )
@ -178,7 +175,7 @@ void AudioInputConfig::load()
//connect( ui.allowIpDeterminationCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleIpDetermination(bool) ) ); //connect( ui.allowIpDeterminationCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleIpDetermination(bool) ) );
//connect( ui.allowTunnelConnectionCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleTunnelConnection(bool) ) ); //connect( ui.allowTunnelConnectionCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleTunnelConnection(bool) ) );
qtTick = new QTimer(this); qtTick = new RsProtectedTimer(this);
connect( qtTick, SIGNAL( timeout ( ) ), this, SLOT( on_Tick_timeout() ) ); connect( qtTick, SIGNAL( timeout ( ) ), this, SLOT( on_Tick_timeout() ) );
qtTick->start(20); qtTick->start(20);
/*if (AudioInputRegistrar::qmNew) { /*if (AudioInputRegistrar::qmNew) {

View File

@ -13,14 +13,15 @@ VideoDecoder::VideoDecoder()
} }
VideoEncoder::VideoEncoder() VideoEncoder::VideoEncoder()
:_frame_size(128,128) :_frame_size(256,256)
{ {
} }
bool VideoEncoder::addImage(const QImage& img,uint32_t size_hint,uint32_t& encoded_size) bool VideoEncoder::addImage(const QImage& img,uint32_t size_hint,uint32_t& encoded_size)
{ {
std::cerr << "reducing to " << _frame_size.width() << " x " << _frame_size.height() << std::endl; // std::cerr << "reducing to " << _frame_size.width() << " x " << _frame_size.height() << std::endl;
encodeData(img.scaled(_frame_size,Qt::IgnoreAspectRatio,Qt::SmoothTransformation),size_hint,encoded_size) ; encodeData(img.scaled(_frame_size,Qt::IgnoreAspectRatio,Qt::SmoothTransformation),size_hint,encoded_size) ;
//encodeData(img,size_hint,encoded_size) ;
return true ; return true ;
} }
@ -44,15 +45,51 @@ void VideoDecoder::receiveEncodedData(const unsigned char *data,uint32_t size)
QImage JPEGVideoDecoder::decodeData(const unsigned char *encoded_image_data,uint32_t size) QImage JPEGVideoDecoder::decodeData(const unsigned char *encoded_image_data,uint32_t size)
{ {
QByteArray qb((char*)encoded_image_data,size) ; static const int HEADER_SIZE = 4 ;
// read frame type. Use first 4 bytes to give info about content.
if(size < HEADER_SIZE)
{
std::cerr << "JPEGVideoDecoder::decodeData(): Too small a data packet. size=" << size << std::endl;
return QImage() ;
}
uint32_t flags = encoded_image_data[0] + (encoded_image_data[1] << 8) ;
// un-compress image data
QByteArray qb((char*)&encoded_image_data[HEADER_SIZE],(int)size - HEADER_SIZE) ;
QImage image ; QImage image ;
if(image.loadFromData(qb,"JPEG")) if(!image.loadFromData(qb,"JPEG"))
return image ;
else
{ {
std::cerr << "image.loadFromData(): returned an error.: " << std::endl; std::cerr << "image.loadFromData(): returned an error.: " << std::endl;
return QImage() ; return QImage() ;
} }
// now see if the frame is a differential frame, or just a reference frame.
if(flags & JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME)
{
if(_reference_frame.size() != image.size())
{
std::cerr << "Bad reference frame!" << std::endl;
return image ;
}
QImage res = _reference_frame ;
for(uint32_t i=0;i<image.byteCount();++i)
res.bits()[i] += (image.bits()[i] - 128) & 0xff ; // it should be -128, but we're doing modulo 256 arithmetic
return res ;
}
else
{
_reference_frame = image ;
return image ;
}
} }
void VideoEncoder::setMaximumFrameRate(uint32_t bytes_per_sec) void VideoEncoder::setMaximumFrameRate(uint32_t bytes_per_sec)
@ -66,7 +103,7 @@ void VideoEncoder::setInternalFrameSize(QSize s)
} }
JPEGVideoEncoder::JPEGVideoEncoder() JPEGVideoEncoder::JPEGVideoEncoder()
: _ref_frame_max_distance(10),_ref_frame_count(10) : _ref_frame_max_distance(50),_ref_frame_count(50)
{ {
} }
@ -75,6 +112,7 @@ void JPEGVideoEncoder::encodeData(const QImage& image,uint32_t /* size_hint */,u
// check if we make a diff image, or if we use the full frame. // check if we make a diff image, or if we use the full frame.
QImage encoded_frame ; QImage encoded_frame ;
bool differential_frame ;
if(_ref_frame_count++ < _ref_frame_max_distance && image.size() == _reference_frame.size()) if(_ref_frame_count++ < _ref_frame_max_distance && image.size() == _reference_frame.size())
{ {
@ -82,13 +120,17 @@ void JPEGVideoEncoder::encodeData(const QImage& image,uint32_t /* size_hint */,u
encoded_frame = image ; encoded_frame = image ;
for(uint32_t i=0;i<image.byteCount();++i) for(uint32_t i=0;i<image.byteCount();++i)
encoded_frame.bits()[i] = image.bits()[i] - _reference_frame.bits()[i] + 128 ; encoded_frame.bits()[i] = (image.bits()[i] - _reference_frame.bits()[i]) + 128;
differential_frame = true ;
} }
else else
{ {
_ref_frame_count = 0 ; _ref_frame_count = 0 ;
_reference_frame = image ; _reference_frame = image ;
encoded_frame = image ; encoded_frame = image ;
differential_frame = false ;
} }
QByteArray qb ; QByteArray qb ;
@ -98,9 +140,18 @@ void JPEGVideoEncoder::encodeData(const QImage& image,uint32_t /* size_hint */,u
encoded_frame.save(&buffer,"JPEG") ; encoded_frame.save(&buffer,"JPEG") ;
RsVOIPDataChunk voip_chunk ; RsVOIPDataChunk voip_chunk ;
voip_chunk.data = malloc(qb.size()); voip_chunk.data = malloc(HEADER_SIZE + qb.size());
memcpy(voip_chunk.data,qb.data(),qb.size()) ;
voip_chunk.size = qb.size() ; // build header
uint32_t flags = differential_frame ? JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME : 0x0 ;
((unsigned char *)voip_chunk.data)[0] = flags & 0xff ;
((unsigned char *)voip_chunk.data)[1] = (flags >> 8) & 0xff ;
((unsigned char *)voip_chunk.data)[2] = 0 ;
((unsigned char *)voip_chunk.data)[3] = 0 ;
memcpy(voip_chunk.data+HEADER_SIZE,qb.data(),qb.size()) ;
voip_chunk.size = HEADER_SIZE + qb.size() ;
voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ;
_out_queue.push_back(voip_chunk) ; _out_queue.push_back(voip_chunk) ;

View File

@ -80,8 +80,11 @@ class JPEGVideoDecoder: public VideoDecoder
protected: protected:
virtual QImage decodeData(const unsigned char *encoded_image,uint32_t encoded_image_size) ; virtual QImage decodeData(const unsigned char *encoded_image,uint32_t encoded_image_size) ;
static const uint32_t HEADER_SIZE = 0x04 ;
static const uint32_t JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME = 0x0001 ;
private: private:
QImage _last_reference_frame ; QImage _reference_frame ;
}; };
class JPEGVideoEncoder: public VideoEncoder class JPEGVideoEncoder: public VideoEncoder
@ -92,6 +95,9 @@ public:
protected: protected:
virtual void encodeData(const QImage& Image, uint32_t size_hint, uint32_t &encoded_size) ; virtual void encodeData(const QImage& Image, uint32_t size_hint, uint32_t &encoded_size) ;
static const uint32_t HEADER_SIZE = 0x04 ;
static const uint32_t JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME = 0x0001 ;
private: private:
QImage _reference_frame ; QImage _reference_frame ;
uint32_t _ref_frame_max_distance ; // max distance between two reference frames. uint32_t _ref_frame_max_distance ; // max distance between two reference frames.

View File

@ -76,6 +76,19 @@ std::ostream& RsVOIPProtocolItem::print(std::ostream &out, uint16_t indent)
printRsItemEnd(out, "RsVOIPProtocolItem", indent); printRsItemEnd(out, "RsVOIPProtocolItem", indent);
return out; return out;
} }
std::ostream& RsVOIPBandwidthItem::print(std::ostream &out, uint16_t indent)
{
printRsItemBase(out, "RsVOIPBandwidthItem", indent);
uint16_t int_Indent = indent + 2;
printIndent(out, int_Indent);
out << "flags: " << std::hex << flags << std::dec << std::endl;
printIndent(out, int_Indent);
out << "speed: " << bytes_per_sec << std::endl;
printRsItemEnd(out, "RsVOIPBandwidthItem", indent);
return out;
}
std::ostream& RsVOIPDataItem::print(std::ostream &out, uint16_t indent) std::ostream& RsVOIPDataItem::print(std::ostream &out, uint16_t indent)
{ {
printRsItemBase(out, "RsVOIPDataItem", indent); printRsItemBase(out, "RsVOIPDataItem", indent);
@ -100,6 +113,14 @@ uint32_t RsVOIPDataItem::serial_size() const
return s; return s;
} }
uint32_t RsVOIPBandwidthItem::serial_size() const
{
uint32_t s = 8; /* header */
s += 4; /* flags */
s += 4; /* bandwidth */
return s;
}
uint32_t RsVOIPProtocolItem::serial_size() const uint32_t RsVOIPProtocolItem::serial_size() const
{ {
uint32_t s = 8; /* header */ uint32_t s = 8; /* header */
@ -150,6 +171,40 @@ bool RsVOIPProtocolItem::serialise(void *data, uint32_t& pktsize)
return ok; return ok;
} }
bool RsVOIPBandwidthItem::serialise(void *data, uint32_t& pktsize)
{
uint32_t tlvsize = serial_size() ;
uint32_t offset = 0;
if (pktsize < tlvsize)
return false; /* not enough space */
pktsize = tlvsize;
bool ok = true;
ok &= setRsItemHeader(data, tlvsize, PacketId(), tlvsize);
#ifdef RSSERIAL_DEBUG
std::cerr << "RsVOIPSerialiser::serialiseVOIPBandwidthItem() Header: " << ok << std::endl;
std::cerr << "RsVOIPSerialiser::serialiseVOIPBandwidthItem() Size: " << tlvsize << std::endl;
#endif
/* skip the header */
offset += 8;
/* add mandatory parts first */
ok &= setRawUInt32(data, tlvsize, &offset, flags);
ok &= setRawUInt32(data, tlvsize, &offset, bytes_per_sec);
if (offset != tlvsize)
{
ok = false;
std::cerr << "RsVOIPSerialiser::serialiseVOIPBandwidthItem() Size Error! " << std::endl;
}
return ok;
}
/* serialise the data to the buffer */ /* serialise the data to the buffer */
bool RsVOIPDataItem::serialise(void *data, uint32_t& pktsize) bool RsVOIPDataItem::serialise(void *data, uint32_t& pktsize)
{ {
@ -254,6 +309,36 @@ RsVOIPProtocolItem::RsVOIPProtocolItem(void *data, uint32_t pktsize)
if (!ok) if (!ok)
throw std::runtime_error("Deserialisation error!") ; throw std::runtime_error("Deserialisation error!") ;
} }
RsVOIPBandwidthItem::RsVOIPBandwidthItem(void *data, uint32_t pktsize)
: RsVOIPItem(RS_PKT_SUBTYPE_VOIP_BANDWIDTH)
{
/* get the type and size */
uint32_t rstype = getRsItemId(data);
uint32_t rssize = getRsItemSize(data);
uint32_t offset = 0;
if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || (RS_SERVICE_TYPE_VOIP_PLUGIN != getRsItemService(rstype)) || (RS_PKT_SUBTYPE_VOIP_BANDWIDTH != getRsItemSubType(rstype)))
throw std::runtime_error("Wrong packet type!") ;
if (pktsize < rssize) /* check size */
throw std::runtime_error("Not enough size!") ;
bool ok = true;
/* skip the header */
offset += 8;
/* get mandatory parts first */
ok &= getRawUInt32(data, rssize, &offset, &flags);
ok &= getRawUInt32(data, rssize, &offset, &bytes_per_sec);
if (offset != rssize)
throw std::runtime_error("Deserialisation error!") ;
if (!ok)
throw std::runtime_error("Deserialisation error!") ;
}
RsVOIPPingItem::RsVOIPPingItem(void *data, uint32_t pktsize) RsVOIPPingItem::RsVOIPPingItem(void *data, uint32_t pktsize)
: RsVOIPItem(RS_PKT_SUBTYPE_VOIP_PING) : RsVOIPItem(RS_PKT_SUBTYPE_VOIP_PING)
{ {

View File

@ -58,8 +58,9 @@ const uint16_t RS_SERVICE_TYPE_VOIP_PLUGIN = 0xa021;
const uint8_t RS_PKT_SUBTYPE_VOIP_PING = 0x01; const uint8_t RS_PKT_SUBTYPE_VOIP_PING = 0x01;
const uint8_t RS_PKT_SUBTYPE_VOIP_PONG = 0x02; const uint8_t RS_PKT_SUBTYPE_VOIP_PONG = 0x02;
const uint8_t RS_PKT_SUBTYPE_VOIP_PROTOCOL = 0x03 ; const uint8_t RS_PKT_SUBTYPE_VOIP_PROTOCOL = 0x03 ;
// 0x04 is unused because of a change in the protocol // 0x04,0x05 is unused because of a change in the protocol
const uint8_t RS_PKT_SUBTYPE_VOIP_DATA = 0x05 ; const uint8_t RS_PKT_SUBTYPE_VOIP_BANDWIDTH = 0x06 ;
const uint8_t RS_PKT_SUBTYPE_VOIP_DATA = 0x07 ;
const uint8_t QOS_PRIORITY_RS_VOIP = 9 ; const uint8_t QOS_PRIORITY_RS_VOIP = 9 ;
@ -117,9 +118,27 @@ class RsVOIPDataItem: public RsVOIPItem
uint32_t flags ; uint32_t flags ;
uint32_t data_size ; uint32_t data_size ;
void *voip_data ; void *voip_data ;
}; };
class RsVOIPBandwidthItem: public RsVOIPItem
{
public:
RsVOIPBandwidthItem() :RsVOIPItem(RS_PKT_SUBTYPE_VOIP_BANDWIDTH) {}
RsVOIPBandwidthItem(void *data,uint32_t size) ; // de-serialization
virtual bool serialise(void *data,uint32_t& size) ;
virtual uint32_t serial_size() const ;
virtual ~RsVOIPBandwidthItem() {}
virtual std::ostream& print(std::ostream &out, uint16_t indent = 0);
uint32_t flags ; // is that incoming or expected bandwidth?
uint32_t bytes_per_sec ; // bandwidth in bytes per sec.
};
class RsVOIPProtocolItem: public RsVOIPItem class RsVOIPProtocolItem: public RsVOIPItem
{ {
public: public: