├── .gitignore ├── CMakeLists.txt ├── L4S-Results.pdf ├── LICENSE ├── README.md ├── SCReAM-BW-test-tool.docx ├── SCReAM-BW-test-tool.pptx ├── SCReAM-description.pptx ├── SCReAM-test-tool-one-pager.pptx ├── Sierra-RV50X-logger.py ├── code ├── CMakeLists.txt ├── NetQueue.cpp ├── NetQueue.h ├── OooQueue.cpp ├── OooQueue.h ├── RtpQueue.cpp ├── RtpQueue.h ├── ScreamRx.cpp ├── ScreamRx.h ├── ScreamTx.cpp ├── ScreamTx.h ├── ScreamV2Tx.cpp ├── ScreamV2Tx.h ├── ScreamV2TxStream.cpp ├── TxList.h ├── VideoEnc.cpp ├── VideoEnc.h ├── scream_01.vcxproj ├── scream_01.vcxproj.user ├── scream_receiver.cpp ├── scream_sender.cpp ├── scream_v_a.cpp ├── stdafx.cpp ├── stdafx.h ├── targetver.h └── wrapper_lib │ ├── CMakeLists.txt │ ├── meson.build │ ├── screamtx_plugin_wrapper.cpp │ └── screamtxbw_plugin_wrapper.cpp ├── examples ├── trace-dualpi-50Mbps-25ms-l4s-txrx.txt ├── trace-dualpi-50Mbps-25ms-l4s.txt ├── trace-dualpi-50Mbps-25ms-nol4s-txrx.txt └── trace-dualpi-50Mbps-25ms-nol4s.txt ├── gstscream ├── .gitignore ├── 2717.patch ├── Cargo.lock ├── Cargo.toml ├── README.md ├── build.rs ├── scripts │ ├── build.sh │ ├── env.sh │ ├── receiver.sh │ ├── receiver_3.sh │ ├── receiver_bw.sh │ ├── screamtx_stats.py │ ├── sender.sh │ ├── sender_3.sh │ ├── sender_bw.sh │ └── sysctl.sh ├── src │ ├── lib.rs │ ├── receiver.rs │ ├── screamrx │ │ ├── ScreamRx.rs │ │ ├── ecn.rs │ │ ├── imp.rs │ │ └── mod.rs │ ├── screamtx │ │ ├── imp.rs │ │ └── mod.rs │ ├── screamtxbw │ │ ├── imp.rs │ │ └── mod.rs │ ├── sender.rs │ └── sender_util.rs └── udp_ecn_diff.txt ├── images ├── L4S-100Mbps-25ms-0-4-0-TCP.png ├── L4S-100Mbps-25ms-0-4-TCP.png ├── L4S-100Mbps-25ms-r-50-0-4-TCP.png ├── SCReAM-V2-L4S.png ├── SCReAM-V2-RTT-25ms-1360B.png ├── SCReAM-V2-noL4S.png ├── SCReAM_LTE_UL.png ├── image_1.png ├── image_2.png ├── scream_ecn.png ├── scream_ecn_2.png ├── scream_ecn_keyframe.png ├── scream_l4s.png ├── scream_l4s_2.png ├── scream_noecn.png ├── scream_noecn_2.png └── scream_noecn_keyframe.png ├── multicam ├── README.md ├── receiver │ ├── LICENSE.dat │ ├── README.md │ ├── killitall.sh │ ├── rendermedia-intel.sh │ ├── rendermedia.sh │ ├── scream │ │ ├── CMakeLists.txt │ │ └── code │ │ │ ├── CMakeLists.txt │ │ │ └── scream_receiver.cpp │ ├── startreceiver-intel.sh │ └── startreceiver.sh └── sender │ ├── 6_bkg_L4S_flows.scream │ ├── LICENSE.dat │ ├── README.md │ ├── default.scream │ ├── gst-codec-ctrl │ └── gst-plugin │ │ ├── AUTHORS │ │ ├── COPYING │ │ ├── ChangeLog │ │ ├── INSTALL │ │ ├── Makefile.am │ │ ├── Makefile.in │ │ ├── NEWS │ │ ├── README │ │ ├── aclocal.m4 │ │ ├── autogen.sh │ │ ├── autom4te.cache │ │ ├── output.0 │ │ ├── output.1 │ │ ├── requests │ │ ├── traces.0 │ │ └── traces.1 │ │ ├── compile │ │ ├── config.guess │ │ ├── config.h │ │ ├── config.h.in │ │ ├── config.h.in~ │ │ ├── config.log │ │ ├── config.status │ │ ├── config.sub │ │ ├── configure │ │ ├── configure.ac │ │ ├── depcomp │ │ ├── install-sh │ │ ├── libtool │ │ ├── ltmain.sh │ │ ├── missing │ │ ├── src │ │ ├── .deps │ │ │ └── libgstcodecctrl_la-gstcodecctrl.Plo │ │ ├── .libs │ │ │ ├── libgstcodecctrl.exp │ │ │ ├── libgstcodecctrl.lai │ │ │ └── libgstcodecctrl.so │ │ ├── Makefile.am │ │ ├── Makefile.in │ │ ├── gstcodecctrl.cpp │ │ ├── gstcodecctrl.h │ │ ├── gstplugin.cpp │ │ ├── gstplugin.h │ │ ├── gsttransform.c │ │ ├── gsttransform.h │ │ └── targetver.h │ │ └── stamp-h1 │ ├── killitall.sh │ ├── scream │ ├── CMakeLists.txt │ └── code │ │ ├── CMakeLists.txt │ │ └── scream_sender.cpp │ ├── startsender.sh │ └── startsender_2.sh ├── plot_1_stream.m ├── plot_1_stream_s.m ├── plot_4_stream.m ├── plot_cdf.m ├── plot_thp_delay.m ├── plot_thp_delay_new.m ├── plot_txrx.m ├── scream.sln ├── scream_ecn_keyframe.png ├── scream_noecn_keyframe.png ├── test-record.md ├── test_v_a.m ├── traces ├── trace_flat.txt ├── trace_key.txt └── trace_no_key.txt └── version-history.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.la 3 | *.lo 4 | *.o 5 | CMakeCache.txt 6 | CMakeFiles/ 7 | Makefile 8 | bin/ 9 | cmake_install.cmake 10 | code/gscream/gscream_app_rpi_tx 11 | code/gscream/gscream_app_rx 12 | code/gscream/gscream_app_tx 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | PROJECT( scream ) 4 | 5 | message("Source Dir:" ${scream_SOURCE_DIR}) 6 | 7 | SET(EXECUTABLE_OUTPUT_PATH ${scream_SOURCE_DIR}/bin) 8 | SET(LIBRARY_OUTPUT_PATH ${scream_SOURCE_DIR}/lib) 9 | SET(RUNTIME_OUTPUT_DIRECTORY ${scream_SOURCE_DIR}/bin) 10 | 11 | SET(scream_BIN ${scream_SOURCE_DIR}/bin) 12 | 13 | message("scream_SOURCE_DIR directories:" ${scream_SOURCE_DIR}) 14 | 15 | IF(UNIX) 16 | add_definitions(-std=c++0x) 17 | ENDIF(UNIX) 18 | 19 | IF(WIN32) 20 | IF(MSVC12) 21 | message("Detected MSVC12 compiler") 22 | set(MSVC_VER VC12) 23 | ELSEIF(MSVC11) 24 | message("Detected MSVC11 compiler") 25 | set(MSVC_VER VC11) 26 | ELSEIF(MSVC10) 27 | message("Detected MSVC10 compiler") 28 | set(MSVC_VER VC10) 29 | ELSEIF(MSVC14) 30 | message("Detected MSVC14 compiler") 31 | set(MSVC_VER VC14) 32 | ELSE(MSVC12) 33 | message("WARNING: Unknown/unsupported MSVC version") 34 | ENDIF(MSVC12) 35 | ENDIF(WIN32) 36 | 37 | if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) 38 | # 64bit 39 | message("Detected 64-bit build - compiling with -fPIC") 40 | SET(CMAKE_CXX_FLAGS "-fPIC -fpermissive -pthread -DV2") 41 | else( CMAKE_SIZEOF_VOID_P EQUAL 8 ) 42 | # 32 bit 43 | message("Detected 32-bit build") 44 | SET(CMAKE_CXX_FLAGS "-fPIC -fpermissive -pthread -DV2") 45 | endif( CMAKE_SIZEOF_VOID_P EQUAL 8 ) 46 | 47 | SET(screamIncludes 48 | ${scream_SOURCE_DIR} 49 | ${scream_SOURCE_DIR}/code 50 | ) 51 | 52 | message("screamIncludes directories:" ${screamIncludes}) 53 | 54 | # lib directories 55 | IF(WIN32) 56 | SET(screamLink 57 | ${scream_SOURCE_DIR}/../lib 58 | ) 59 | ELSEIF(UNIX) 60 | SET(screamLink 61 | ${scream_SOURCE_DIR}/../lib 62 | /usr/local/lib 63 | /usr/lib 64 | ) 65 | ENDIF(WIN32) 66 | 67 | SET(LibDir 68 | ${scream_SOURCE_DIR}/../lib 69 | ) 70 | 71 | message("LibDir directories:" ${LibDir}) 72 | 73 | # Include directories 74 | INCLUDE_DIRECTORIES( 75 | ${scream_SOURCE_DIR}/../include 76 | ) 77 | 78 | ADD_SUBDIRECTORY( code) 79 | -------------------------------------------------------------------------------- /L4S-Results.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/L4S-Results.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Ericsson AB. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this 10 | list of conditions and the following disclaimer in the documentation and/or other 11 | materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 17 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 19 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 20 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 21 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 22 | OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /SCReAM-BW-test-tool.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/SCReAM-BW-test-tool.docx -------------------------------------------------------------------------------- /SCReAM-BW-test-tool.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/SCReAM-BW-test-tool.pptx -------------------------------------------------------------------------------- /SCReAM-description.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/SCReAM-description.pptx -------------------------------------------------------------------------------- /SCReAM-test-tool-one-pager.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/SCReAM-test-tool-one-pager.pptx -------------------------------------------------------------------------------- /Sierra-RV50X-logger.py: -------------------------------------------------------------------------------- 1 | 2 | import requests 3 | import json 4 | import datetime 5 | import time 6 | import socket 7 | 8 | # OUT_FILE = 'data.txt' 9 | # This simple application logs the Sierra RV50X (possibly other Sierra modems too) 10 | # The data is echoed to 127.0.0.1:35000, the SCReAM wrappers can get the data this 11 | # way and then include it the SCReAM logging 12 | # >python3 Sierra-RV50X-logger.py 13 | 14 | 15 | base_url = 'http://192.168.13.31:9191' 16 | username = 'user' 17 | password = '12345' 18 | 19 | login_url = '{}/xml/Connect.xml'.format(base_url) 20 | login_payload = ''' 21 | 22 | {} 23 | 24 | 25 | '''.format(username, password) 26 | 27 | req_url = '{}/cgi-bin/Embedded_Ace_Get_Task.cgi'.format(base_url) 28 | req_headers = { 29 | 'Content-Type': 'text/xml', 30 | } 31 | 32 | # Param name to id map 33 | param_ids = { 34 | 'Cellular IP Address': 303, 35 | 'ESN/EID/IMEI': 10, 36 | 'Active Frequency Band': 671, 37 | 'SIM ID': 771, 38 | 'Cell ID': 773, 39 | 'RSRP': 10210, 40 | 'SINR': 10209, 41 | 'RSSI': 261, 42 | } 43 | 44 | param_names = dict(map(lambda tup: (tup[1], tup[0]), param_ids.items())) 45 | 46 | # payload = '303,12001,12002,10,771,11202,10701,10702,10704,785,773,774,775,671,674,672,675,1105,1104,10230,10298,5030,1082,1083,12005,12006,1091,1136,2753,5046,283,284,10283,10284,281,282,51006,52007,52008,53000,53101,53200,12003,12003,12003,12003' 47 | #payload = '303,12001,10' 48 | payload = '10210,10209,261,773' 49 | 50 | def make_params_payload(params): 51 | param_list = map(lambda param: str(param_ids[param]), params) 52 | return ','.join(param_list) 53 | 54 | def parse_pair(pair): 55 | [pid_str, value] = pair.split('=') 56 | pid = int(pid_str) 57 | param_name = param_names[pid] if pid in param_names else 'param {}'.format(pid) 58 | return (param_name, value) 59 | 60 | def parse_params(data): 61 | pairs = data.split('!')[:-1] 62 | return dict(map(lambda pair: parse_pair(pair), pairs)) 63 | 64 | def make_request(params): 65 | with requests.Session() as s: 66 | p = s.post(login_url, data=login_payload) 67 | print('login response text:', p.text) 68 | 69 | #payload = make_params_payload(params) 70 | 71 | r = s.post(req_url, headers=req_headers, data=payload) 72 | # print('request text:', r.text) 73 | 74 | return { 75 | 'timestamp': datetime.datetime.now().isoformat(), 76 | 'data': parse_params(r.text), 77 | } 78 | # return None 79 | 80 | def send_to_udp_socket(result): 81 | UDP_IP = "127.0.0.1" 82 | UDP_PORT = 35000 83 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 84 | sock.sendto(bytes(result, 'utf-8'), (UDP_IP, UDP_PORT)) 85 | 86 | # params = ['Cellular IP Address', 'ESN/EID/IMEI'] 87 | params = param_ids.keys() 88 | try: 89 | while True: 90 | result = make_request(params) 91 | #result = make_request(payload) 92 | #print('result:', json.dumps(result, indent=4)) 93 | print(result) 94 | send_to_udp_socket(json.dumps(result)) 95 | time.sleep(1) 96 | except KeyboardInterrupt: 97 | print('\n Terminated from keyboard. \n') 98 | 99 | 100 | # with open(OUT_FILE, 'a') as f: 101 | # f.write('row\n') 102 | -------------------------------------------------------------------------------- /code/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # source files 2 | 3 | SET(HEADERS 4 | ScreamRx.h 5 | ScreamTx.h 6 | RtpQueue.h 7 | ) 8 | 9 | SET(SRC_SENDER 10 | ScreamTx.cpp 11 | ScreamV2Tx.cpp 12 | ScreamV2TxStream.cpp 13 | RtpQueue.cpp 14 | scream_sender.cpp 15 | ) 16 | 17 | SET(SRC_RECEIVER 18 | ScreamRx.cpp 19 | scream_receiver.cpp 20 | ) 21 | 22 | set(CMAKE_BUILD_TYPE Debug) 23 | 24 | INCLUDE_DIRECTORIES( 25 | ${screamIncludes} 26 | ) 27 | 28 | LINK_DIRECTORIES( 29 | ${screamLink} 30 | ) 31 | 32 | ADD_EXECUTABLE(scream_bw_test_tx ${SRC_SENDER} ${HEADERS}) 33 | ADD_EXECUTABLE(scream_bw_test_rx ${SRC_RECEIVER} ${HEADERS}) 34 | 35 | TARGET_LINK_LIBRARIES ( 36 | scream_bw_test_tx 37 | ${screamLibs} pthread 38 | ) 39 | 40 | TARGET_LINK_LIBRARIES ( 41 | scream_bw_test_rx 42 | ${screamLibs} pthread 43 | ) 44 | -------------------------------------------------------------------------------- /code/NetQueue.cpp: -------------------------------------------------------------------------------- 1 | #include "NetQueue.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | /* 10 | * Implements a simple RTP packet queue 11 | */ 12 | 13 | const float l4sThLo = 0.004f; 14 | const float l4sThHi = 0.008f; 15 | NetQueueItem::NetQueueItem() { 16 | packet = 0; 17 | used = false; 18 | size = 0; 19 | seqNr = 0; 20 | timeStamp = 0; 21 | tRelease = 0.0; 22 | tQueue = 0.0; 23 | } 24 | 25 | NetQueue::NetQueue(float delay_, float rate_, float jitter_, bool isL4s_) { 26 | for (int n=0; n < NetQueueSize; n++) { 27 | items[n] = new NetQueueItem(); 28 | } 29 | head = -1; 30 | tail = 0; 31 | nItems = 0; 32 | rate = rate_; 33 | delay = delay_; 34 | jitter = jitter_; 35 | lastQueueLow = 0.0; 36 | // nextTx = 0; 37 | sendTime = 0; 38 | isL4s = isL4s_; 39 | bytesTx = 0; 40 | lastRateUpdateT = 0; 41 | pDrop = 0.0f; 42 | prevRateFrac = 0.0f; 43 | tQueueAvg = 0.0; 44 | 45 | } 46 | 47 | float pMarkList[] = {0.0,0.5000,1.0000,1.5000,2.0000,5.0000,10.0000,20.0000,30.0000,40.0000,50.0000 }; 48 | float markCarry = 0.0f; 49 | void NetQueue::insert(float time, 50 | void* rtpPacket, 51 | unsigned int ssrc, 52 | int size, 53 | unsigned short seqNr, 54 | bool isCe, 55 | bool isMark, 56 | unsigned int timeStamp) { 57 | int prevHead = head; 58 | if (false && nItems > 1000) 59 | return; 60 | nItems++; 61 | head++; if (head == NetQueueSize) head = 0; 62 | items[head]->used = true; 63 | items[head]->packet = rtpPacket; 64 | items[head]->ssrc = ssrc; 65 | items[head]->size = size; 66 | items[head]->seqNr = seqNr; 67 | items[head]->timeStamp = timeStamp; 68 | float tmp = 0; 69 | if (rate > 0) 70 | tmp += size * 8 / rate; 71 | sendTime = std::max(sendTime, time) + tmp; 72 | items[head]->tRelease = sendTime + delay + jitter * (rand() / float(RAND_MAX));; 73 | items[head]->tQueue = time; 74 | if (rate > 0) { 75 | float qDelay = items[tail]->tRelease - items[tail]->tQueue; 76 | if (isL4s) { 77 | int ix = int(time / 60.0f); 78 | //float pMark = pMarkList[ix] / 100.0; 79 | float pMark = std::max(0.0f, std::min(1.0f, (qDelay - l4sThLo) / (l4sThHi - l4sThLo))); 80 | markCarry += pMark; 81 | //if (markCarry >= 1.0f) { 82 | if ((rand() % 1000) / 1000.0 < pMark) { 83 | markCarry -= 1.0f; 84 | isCe = true; 85 | } 86 | } else { 87 | if (qDelay > 0.03) { 88 | isCe = true; 89 | } 90 | } 91 | } 92 | 93 | 94 | items[head]->isCe = isCe; 95 | items[head]->isMark = isMark; 96 | } 97 | 98 | bool NetQueue::extract(float time, 99 | void* rtpPacket, 100 | unsigned int& ssrc, 101 | int& size, 102 | unsigned short& seqNr, 103 | bool& isCe, 104 | bool& isMark, 105 | unsigned int& timeStamp) { 106 | if (items[tail]->used == false) { 107 | lastQueueLow = time; 108 | return false; 109 | } 110 | else { 111 | if (time >= items[tail]->tRelease) { 112 | // items[tail]->tReleaseExt = time; 113 | rtpPacket = items[tail]->packet; 114 | seqNr = items[tail]->seqNr; 115 | timeStamp = items[tail]->timeStamp; 116 | ssrc = items[tail]->ssrc; 117 | size = items[tail]->size; 118 | isCe = items[tail]->isCe; 119 | isMark = items[tail]->isMark; 120 | 121 | items[tail]->used = false; 122 | 123 | bytesTx += size; 124 | tail++; if (tail == NetQueueSize) tail = 0; 125 | nItems = std::max(0, nItems - 1); 126 | 127 | return true; 128 | } 129 | return false; 130 | } 131 | } 132 | 133 | 134 | 135 | 136 | int NetQueue::sizeOfQueue() { 137 | int size = 0; 138 | for (int n=0; n < NetQueueSize; n++) { 139 | if (items[n]->used) 140 | size += items[n]->size; 141 | } 142 | return size; 143 | } 144 | 145 | const float rateUpdateT = 0.05f; 146 | 147 | void NetQueue::updateRate(float time) { 148 | if (time - lastRateUpdateT >= rateUpdateT && rate > 0) { 149 | float dT = time - lastRateUpdateT; 150 | float rateT = bytesTx * 8 / dT; 151 | bytesTx = 0; 152 | lastRateUpdateT = time; 153 | float rateFrac = rateT / rate - 0.9f; 154 | rateFrac /= 0.2f; 155 | rateFrac = std::max(0.0f, std::min(1.0f, rateFrac)); 156 | pDrop = 0.9f*pDrop + 0.1f*rateFrac; 157 | pDrop = std::min(1.0f, std::max(0.0f, pDrop)); 158 | prevRateFrac = rateFrac; 159 | if (false && pDrop > 0) 160 | cerr << pDrop << endl;; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /code/NetQueue.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_QUEUE 2 | #define NET_QUEUE 3 | 4 | 5 | class NetQueueItem { 6 | public: 7 | NetQueueItem(); 8 | void* packet; 9 | unsigned int ssrc; 10 | int size; 11 | unsigned short seqNr; 12 | unsigned int timeStamp; 13 | float tRelease; 14 | // float tReleaseExt; 15 | float tQueue; 16 | bool isCe; 17 | bool isMark; 18 | bool used; 19 | }; 20 | const int NetQueueSize = 10000; 21 | class NetQueue { 22 | public: 23 | 24 | NetQueue(float delay, float rate=0.0f, float jitter=0.0f, bool isL4s = false); 25 | 26 | void insert(float time, 27 | void *rtpPacket, 28 | unsigned int ssrc, 29 | int size, 30 | unsigned short seqNr, 31 | bool isCe, 32 | bool isMark, 33 | unsigned int timeStamp); 34 | bool extract(float time, 35 | void *rtpPacket, 36 | unsigned int &ssrc, 37 | int& size, 38 | unsigned short &seqNr, 39 | bool &isCe, 40 | bool &isMark, 41 | unsigned int& timeStamp); 42 | int sizeOfQueue(); 43 | 44 | void updateRate(float time); 45 | 46 | NetQueueItem *items[NetQueueSize]; 47 | int head; // Pointer to last inserted item 48 | int tail; // Pointer to the oldest item 49 | int nItems; 50 | float delay; 51 | float rate; 52 | float jitter; 53 | float sendTime; 54 | // float nextTx; 55 | float lastQueueLow; 56 | bool isL4s; 57 | int bytesTx; 58 | float lastRateUpdateT; 59 | float pDrop; 60 | float prevRateFrac; 61 | float tQueueAvg; 62 | }; 63 | 64 | #endif -------------------------------------------------------------------------------- /code/OooQueue.cpp: -------------------------------------------------------------------------------- 1 | #include "OooQueue.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | /* 10 | * Implements a simple RTP packet queue 11 | */ 12 | 13 | OooQueueItem::OooQueueItem() { 14 | packet = 0; 15 | used = false; 16 | size = 0; 17 | seqNr = 0; 18 | tRelease = 0.0; 19 | tQueue = 0.0; 20 | } 21 | 22 | OooQueue::OooQueue(float maxDelay_) { 23 | for (int n=0; n < OooQueueSize; n++) { 24 | items[n] = new OooQueueItem(); 25 | } 26 | item = new OooQueueItem(); 27 | nItems = 0; 28 | maxDelay = maxDelay_; 29 | prevTRelease = 0; 30 | nDelayed; 31 | } 32 | 33 | bool OooQueue::insert(float time, 34 | void* rtpPacket, 35 | unsigned int ssrc, 36 | int size, 37 | unsigned short seqNr, 38 | bool isCe, 39 | bool isMark, 40 | unsigned int timeStamp) { 41 | 42 | float delay = maxDelay; //rand()* maxDelay / RAND_MAX; 43 | //if (delay > 0.0001f) { 44 | if (maxDelay > 0.0f && (seqNr % 2048 < 20) && seqNr > 100 && seqNr % 1 == 0) {//}&& seqNr < 3000) { 45 | /* 46 | * put in queue to apply OOO delay 47 | */ 48 | int ix = -1; 49 | for (int n = 0; n < OooQueueSize; n++) { 50 | if (!items[n]->used) { 51 | ix = n; 52 | continue; 53 | } 54 | } 55 | if (ix == -1) { 56 | cerr << "Too many OOO packets, increase OooQueueSize" << endl; 57 | exit(-1); 58 | } 59 | OooQueueItem* tmp = item; 60 | tmp->tRelease = time; 61 | tmp = items[ix]; 62 | //cerr << time << " " << seqNr << endl; 63 | if (false || nDelayed == 0) { 64 | tmp->tRelease = time + delay; 65 | } 66 | else { 67 | //tmp->tRelease = time + maxDelay; 68 | tmp->tRelease = prevTRelease - 0.0001; 69 | } 70 | prevTRelease = tmp->tRelease; 71 | tmp->used = true; 72 | tmp->packet = rtpPacket; 73 | tmp->ssrc = ssrc; 74 | tmp->size = size; 75 | tmp->seqNr = seqNr; 76 | tmp->timeStamp = timeStamp; 77 | tmp->isCe = isCe; 78 | tmp->isMark = isMark; 79 | tmp->tQueue = time; 80 | nDelayed++; 81 | return true; 82 | } 83 | nDelayed = 0; 84 | 85 | return false; 86 | } 87 | 88 | bool OooQueue::extract(float time, 89 | void* rtpPacket, 90 | unsigned int& ssrc, 91 | int& size, 92 | unsigned short& seqNr, 93 | bool& isCe, 94 | bool& isMark, 95 | unsigned int& timeStamp) { 96 | 97 | OooQueueItem* tmp = item; 98 | for (int n = 0; n < OooQueueSize; n++) { 99 | if (items[n]->used && items[n]->tRelease < time) { 100 | tmp = items[n]; 101 | } 102 | } 103 | 104 | if (tmp->used) { 105 | rtpPacket = tmp->packet; 106 | seqNr = tmp->seqNr; 107 | timeStamp = tmp->timeStamp; 108 | ssrc = tmp->ssrc; 109 | size = tmp->size; 110 | isCe = tmp->isCe; 111 | isMark = tmp->isMark; 112 | tmp->used = false; 113 | 114 | return true; 115 | } else { 116 | return false; 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /code/OooQueue.h: -------------------------------------------------------------------------------- 1 | #ifndef OOO_QUEUE 2 | #define OOO_QUEUE 3 | 4 | 5 | class OooQueueItem { 6 | public: 7 | OooQueueItem(); 8 | void* packet; 9 | unsigned int ssrc; 10 | int size; 11 | unsigned short seqNr; 12 | unsigned long timeStamp; 13 | float tRelease; 14 | float tQueue; 15 | bool isCe; 16 | bool isMark; 17 | bool used; 18 | }; 19 | const int OooQueueSize = 512; 20 | class OooQueue { 21 | public: 22 | 23 | OooQueue(float maxDelay); 24 | 25 | /* 26 | * Return true of packet is delayed, otherwise false 27 | */ 28 | bool insert(float time, 29 | void *rtpPacket, 30 | unsigned int ssrc, 31 | int size, 32 | unsigned short seqNr, 33 | bool isCe, 34 | bool isMark, 35 | unsigned int timeStamp); 36 | bool extract(float time, 37 | void* rtpPacket, 38 | unsigned int& ssrc, 39 | int& size, 40 | unsigned short& seqNr, 41 | bool& isCe, 42 | bool& isMark, 43 | unsigned int& timeStamp); 44 | 45 | OooQueueItem *items[OooQueueSize]; 46 | OooQueueItem *item; 47 | int nItems; 48 | float maxDelay; 49 | int nDelayed; 50 | float prevTRelease; 51 | }; 52 | 53 | #endif -------------------------------------------------------------------------------- /code/RtpQueue.cpp: -------------------------------------------------------------------------------- 1 | #include "RtpQueue.h" 2 | #include 3 | #include 4 | using namespace std; 5 | /* 6 | * Implements a simple RTP packet queue 7 | */ 8 | 9 | RtpQueueItem::RtpQueueItem() { 10 | used = false; 11 | size = 0; 12 | seqNr = 0; 13 | timeStamp = 0; 14 | } 15 | 16 | 17 | RtpQueue::RtpQueue() { 18 | for (int n = 0; n < kRtpQueueSize; n++) { 19 | items[n] = new RtpQueueItem(); 20 | } 21 | head = -1; 22 | tail = 0; 23 | nItems = 0; 24 | sizeOfLastFrame = 0; 25 | bytesInQueue_ = 0; 26 | sizeOfQueue_ = 0; 27 | sizeOfNextRtp_ = -1; 28 | } 29 | 30 | bool RtpQueue::push(void* rtpPacket, int size, uint32_t ssrc, unsigned short seqNr, bool isMark, float ts, uint32_t timeStamp) { 31 | std::unique_lock lock(queue_operation_mutex_); 32 | int ix = head + 1; 33 | if (ix == kRtpQueueSize) ix = 0; 34 | if (items[ix]->used) { 35 | /* 36 | * RTP queue is full, do a drop tail i.e ignore new RTP packets 37 | */ 38 | return (false); 39 | } 40 | head = ix; 41 | items[head]->seqNr = seqNr; 42 | items[head]->timeStamp = timeStamp; 43 | items[head]->ssrc = ssrc; 44 | items[head]->size = size; 45 | items[head]->ts = ts; 46 | items[head]->isMark = isMark; 47 | items[head]->used = true; 48 | bytesInQueue_ += size; 49 | sizeOfQueue_ += 1; 50 | #ifndef IGNORE_PACKET 51 | items[head]->packet = rtpPacket; 52 | #endif 53 | computeSizeOfNextRtp(); 54 | return (true); 55 | } 56 | bool RtpQueue::pop(void** rtpPacket, int& size, uint32_t& ssrc, unsigned short& seqNr, bool& isMark, uint32_t& timeStamp) 57 | { 58 | std::unique_lock lock(queue_operation_mutex_); 59 | if (items[tail]->used == false) { 60 | *rtpPacket = NULL; 61 | sizeOfNextRtp_ = -1; 62 | return false; 63 | } 64 | else { 65 | size = items[tail]->size; 66 | 67 | #ifndef IGNORE_PACKET 68 | * rtpPacket = items[tail]->packet; 69 | #endif 70 | seqNr = items[tail]->seqNr; 71 | timeStamp = items[tail]->timeStamp; 72 | ssrc = items[tail]->ssrc; 73 | isMark = items[tail]->isMark; 74 | items[tail]->used = false; 75 | /* 76 | * Thread safe update of tail to avoid that tail points outside 77 | * array, which can cause e.g RtpQueue::getDelay to give a 78 | * segmentation fault. 79 | * This should not really be needed because 80 | * we use mutex to make the pop function atomic 81 | */ 82 | if (tail == kRtpQueueSize - 1) 83 | tail = 0; 84 | else 85 | tail++; 86 | bytesInQueue_ -= size; 87 | sizeOfQueue_ -= 1; 88 | computeSizeOfNextRtp(); 89 | return true; 90 | } 91 | } 92 | 93 | void RtpQueue::computeSizeOfNextRtp() { 94 | if (!items[tail]->used) { 95 | sizeOfNextRtp_ = -1; 96 | } 97 | else { 98 | sizeOfNextRtp_ = items[tail]->size; 99 | } 100 | } 101 | 102 | int RtpQueue::sizeOfNextRtp() { 103 | return sizeOfNextRtp_; 104 | } 105 | 106 | int RtpQueue::seqNrOfNextRtp() { 107 | if (!items[tail]->used) { 108 | return -1; 109 | } 110 | else { 111 | return items[tail]->seqNr; 112 | } 113 | } 114 | 115 | int RtpQueue::seqNrOfLastRtp() { 116 | if (!items[head]->used) { 117 | return -1; 118 | } 119 | else { 120 | return items[head]->seqNr; 121 | } 122 | } 123 | 124 | int RtpQueue::bytesInQueue() { 125 | return bytesInQueue_; 126 | } 127 | 128 | int RtpQueue::sizeOfQueue() { 129 | return sizeOfQueue_; 130 | } 131 | 132 | float RtpQueue::getDelay(float currTs) { 133 | if (items[tail]->used == false) { 134 | return 0; 135 | } 136 | else { 137 | return currTs - items[tail]->ts; 138 | } 139 | } 140 | 141 | bool RtpQueue::sendPacket(void** rtpPacket, int& size, uint32_t& ssrc, unsigned short& seqNr, bool& isMark, uint32_t& timeStamp) { 142 | if (sizeOfQueue() > 0) { 143 | pop(rtpPacket, size, ssrc, seqNr, isMark, timeStamp); 144 | return true; 145 | } 146 | return false; 147 | } 148 | 149 | #ifndef IGNORE_PACKET 150 | extern void packet_free(void* buf, uint32_t ssrc); 151 | #endif 152 | int RtpQueue::clear() { 153 | uint16_t seqNr; 154 | uint32_t timeStamp; 155 | uint32_t ssrc; 156 | int freed = 0; 157 | int size; 158 | void* buf; 159 | while (sizeOfQueue() > 0) { 160 | bool isMark; 161 | pop(&buf, size, ssrc, seqNr, isMark, timeStamp); 162 | if (buf != NULL) { 163 | freed++; 164 | #ifndef IGNORE_PACKET 165 | packet_free(buf, ssrc); 166 | #endif 167 | } 168 | } 169 | return (freed); 170 | } 171 | -------------------------------------------------------------------------------- /code/RtpQueue.h: -------------------------------------------------------------------------------- 1 | #ifndef RTP_QUEUE 2 | #define RTP_QUEUE 3 | 4 | #include 5 | #include 6 | /* 7 | * Implements a simple RTP packet queue, one RTP queue 8 | * per stream {SSRC,PT} 9 | */ 10 | 11 | class RtpQueueIface { 12 | public: 13 | virtual int clear() = 0; 14 | virtual int sizeOfNextRtp() = 0; 15 | virtual int seqNrOfNextRtp() = 0; 16 | virtual int seqNrOfLastRtp() = 0; 17 | virtual int bytesInQueue() = 0; // Number of bytes in queue 18 | virtual int sizeOfQueue() = 0; // Number of items in queue 19 | virtual float getDelay(float currTs) = 0; 20 | virtual int getSizeOfLastFrame() = 0; 21 | }; 22 | 23 | class RtpQueueItem { 24 | public: 25 | RtpQueueItem(); 26 | void* packet; 27 | int size; 28 | uint32_t ssrc; 29 | unsigned short seqNr; 30 | unsigned long timeStamp; 31 | float ts; 32 | bool isMark; 33 | bool used; 34 | }; 35 | 36 | const int kRtpQueueSize = 1024; 37 | class RtpQueue : public RtpQueueIface { 38 | public: 39 | RtpQueue(); 40 | 41 | bool push(void* rtpPacket, int size, uint32_t ssrc, unsigned short seqNr, bool isMark, float ts, uint32_t timeStamp); 42 | bool pop(void** rtpPacket, int& size, uint32_t& ssrc, unsigned short& seqNr, bool& isMark, uint32_t& timeStamp); 43 | int sizeOfNextRtp(); 44 | int seqNrOfNextRtp(); 45 | int seqNrOfLastRtp(); 46 | int bytesInQueue(); // Number of bytes in queue 47 | int sizeOfQueue(); // Number of items in queue 48 | float getDelay(float currTs); 49 | bool sendPacket(void** rtpPacket, int& size, uint32_t& ssrc, unsigned short& seqNr, bool& isMark, uint32_t& timeStamp); 50 | int clear(); 51 | int getSizeOfLastFrame() { return sizeOfLastFrame; }; 52 | void setSizeOfLastFrame(int sz) { sizeOfLastFrame = sz; }; 53 | void computeSizeOfNextRtp(); 54 | 55 | RtpQueueItem* items[kRtpQueueSize]; 56 | int head; // Pointer to last inserted item 57 | int tail; // Pointer to the oldest item 58 | int nItems; 59 | int sizeOfLastFrame; 60 | 61 | int bytesInQueue_; 62 | int sizeOfQueue_; 63 | int sizeOfNextRtp_; 64 | std::mutex queue_operation_mutex_; 65 | }; 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /code/ScreamRx.h: -------------------------------------------------------------------------------- 1 | #ifndef SCREAM_RX 2 | #define SCREAM_RX 3 | #include 4 | #include 5 | const int kReportedRtpPackets = 32; 6 | const int kRxHistorySize = 512; 7 | 8 | /* 9 | * This module implements the receiver side of SCReAM. 10 | * As SCReAM is a sender based congestion control, the receiver side is 11 | * actually dumber than dumb. In essense the only thing that it does is to 12 | * + Record receive time stamps and RTP sequence numbers for incoming RTP packets 13 | * + Generate RTCP feedback elements 14 | * + Calculate an appropriate RTCP feedback interval 15 | * See https://github.com/EricssonResearch/scream/blob/master/SCReAM-description.pptx 16 | * for details on how it is integrated in audio/video platforms. 17 | * A full implementation needs the additional code for 18 | * + Other obvious stuff such as RTP payload depacketizer, video+audio deoders, rendering, dejitterbuffers 19 | * It is recommended that RTCP feedback for multiple streams are bundled in one RTCP packet. 20 | * However as low bitrate media (e.g audio) requires a lower feedback rate than high bitrate media (e.g video) 21 | * it is possible to include RTCP feedback for the audio stream more seldom. The code for this is T.B.D 22 | * 23 | * Internal time is represented as the mid 32 bits of the NTP timestamp (see RFC5905) 24 | * This means that the high order 16 bits is time in seconds and the low order 16 bits 25 | * is the fraction. The NTP time stamp is thus in Q16 i.e 1.0sec is represented 26 | * by the value 65536. 27 | * All internal time is measured in NTP time, this is done to avoid wraparound issues 28 | * that can otherwise occur every 18 hour or so 29 | */ 30 | 31 | class ScreamRx { 32 | public: 33 | ScreamRx(uint32_t ssrc, int ackDiff = -1, int nReportedRtpPackets = kReportedRtpPackets); // SSRC of this RTCP session 34 | ~ScreamRx(); 35 | 36 | /* 37 | * One instance is created for each source SSRC 38 | */ 39 | class Stream { 40 | public: 41 | Stream(uint32_t ssrc); 42 | 43 | bool isMatch(uint32_t ssrc_) { return ssrc == ssrc_; }; 44 | 45 | bool checkIfFlushAck(uint32_t ackDiff); 46 | 47 | /* 48 | * Receive RTP packet 49 | */ 50 | void receive(uint32_t time_ntp, 51 | void* rtpPacket, 52 | int size, 53 | uint16_t seqNr, 54 | bool isEcnCe, 55 | uint8_t ceBits, 56 | bool isMarker, 57 | uint32_t timeStamp); 58 | 59 | /* 60 | * Get SCReAM standardized RTCP feedback 61 | * return FALSE if no pending feedback available 62 | */ 63 | bool getStandardizedFeedback(uint32_t time_ntp, 64 | unsigned char* buf, 65 | int& size); 66 | 67 | /* 68 | * Get SCReAM standardized RTCP feedback for OOO RTP packets, i.e packets that 69 | * are received more than kReportedRtpPackets behind highestSeqNrTx 70 | * return FALSE if no pending feedback available 71 | */ 72 | bool getStandardizedFeedbackOoo(uint32_t time_ntp, 73 | unsigned char* buf, 74 | int& size); 75 | 76 | 77 | uint32_t ssrc; // SSRC of stream (source SSRC) 78 | uint32_t receiveTimestamp; // Wall clock time 79 | uint16_t highestSeqNr; // Highest received sequence number 80 | uint16_t highestSeqNrTx; // Highest fed back sequence number 81 | uint16_t oooLowSeqNr; // Lowest OOO RTP received sequence number 82 | int numOooDetected; // Number of OOO RTP packets 83 | 84 | 85 | uint8_t ceBitsHist[kRxHistorySize]; // Vector of CE bits for last 86 | // received RTP packets 87 | uint32_t rxTimeHist[kRxHistorySize]; // Receive time for last 88 | // received RTP packets 89 | uint16_t seqNrHist[kRxHistorySize]; // Seq Nr of last received 90 | // received RTP packets 91 | bool isOooHist[kRxHistorySize]; // Packet is received OOO 92 | uint32_t lastFeedbackT_ntp; // Last time feedback transmitted for 93 | // this SSRC 94 | int nRtpSinceLastRtcp; // Number of RTP packets since last transmitted RTCP 95 | 96 | bool firstReceived; 97 | 98 | int nReportedRtpPackets; 99 | 100 | bool doFlush; 101 | }; 102 | 103 | /* 104 | * Check to ensure that ACKs can cover also large holes in 105 | * in the received sequence number space. These cases can frequently occur when 106 | * SCReAM is used in frame discard mode i.e. when real video rate control is 107 | * not possible 108 | */ 109 | bool checkIfFlushAck(); 110 | 111 | /* 112 | * At least one stream has received OOO RTP packets, this necessitates transmission of 113 | * extra RTCP packets to cover the hole 114 | */ 115 | bool isOooDetected(); 116 | 117 | /* 118 | * Function is called each time an RTP packet is received 119 | */ 120 | void receive(uint32_t time_ntp, 121 | void* rtpPacket, 122 | uint32_t ssrc, 123 | int size, 124 | uint16_t seqNr, 125 | uint8_t ceBits, 126 | bool isMarker, 127 | uint32_t timeStamp); 128 | 129 | /* 130 | * Return TRUE if an RTP packet has been received and there is 131 | * pending feedback 132 | */ 133 | bool isFeedback(uint32_t time_ntp); 134 | 135 | /* 136 | * Return RTCP feedback interval (Q16) 137 | */ 138 | uint32_t getRtcpFbInterval(); 139 | 140 | /* 141 | * Create standardized feedback according to 142 | * https://datatracker.ietf.org/doc/rfc8888/ 143 | * It is up to the wrapper application to prepend this RTCP 144 | * with SR or RR when needed 145 | */ 146 | bool createStandardizedFeedback(uint32_t time_ntp, bool isMark, unsigned char* buf, int& size); 147 | 148 | /* 149 | * Create standardized feedback according to 150 | * https://datatracker.ietf.org/doc/rfc8888/ ... 151 | * That catches up with OOO RTP packets 152 | * It is up to the wrapper application to prepend this RTCP 153 | * with SR or RR when needed 154 | */ 155 | bool createStandardizedFeedbackOoo(uint32_t time_ntp, bool isMark, unsigned char* buf, int& size); 156 | 157 | /* 158 | * Get last feedback transmission time in NTP domain (Q16) 159 | */ 160 | uint32_t getLastFeedbackT() { return lastFeedbackT_ntp; }; 161 | 162 | uint32_t lastFeedbackT_ntp; 163 | int bytesReceived; 164 | uint32_t lastRateComputeT_ntp; 165 | float averageReceivedRate; 166 | uint32_t rtcpFbInterval_ntp; 167 | uint32_t ssrc; 168 | 169 | //int getIx(uint32_t ssrc); 170 | //int ix; 171 | int ackDiff; 172 | 173 | int nReportedRtpPackets; 174 | /* 175 | * Variables for multiple steams handling 176 | */ 177 | std::list streams; 178 | }; 179 | 180 | #endif 181 | -------------------------------------------------------------------------------- /code/ScreamTx.cpp: -------------------------------------------------------------------------------- 1 | #include "ScreamTx.h" 2 | #include 3 | 4 | static const uint32_t kMinTimeForMinMaxStatistics_ntp = 5*65536; 5 | 6 | ScreamTx::ScreamTx() { 7 | statistics = new Statistics(this); 8 | } 9 | 10 | ScreamTx::~ScreamTx() { 11 | delete statistics; 12 | } 13 | 14 | ScreamTx::Statistics::Statistics(ScreamTx* parent_) { 15 | parent = parent_; 16 | sumRateTx = 0.0f; 17 | sumRateLost = 0.0f; 18 | sumRateCe = 0.0f; 19 | avgRateTx = 0.0f; 20 | minRate = 1e9f; 21 | maxRate = 0.0f; 22 | avgRtt = 0.0f; 23 | sumRtt = 0.0f; 24 | minRtt = 10.0f; 25 | maxRtt = 0.0f; 26 | avgQueueDelay = 0.0f; 27 | maxQueueDelay = 0.0f; 28 | lossRate = 0.0f; 29 | lossRateLong = 0.0f; 30 | ceRate = 0.0f; 31 | ceRateLong = 0.0f; 32 | rateLostAcc = 0.0f; 33 | rateCeAcc = 0.0f; 34 | rateLostN = 0; 35 | nStatisticsItems++; 36 | n00 = 0; 37 | n10 = 0; 38 | n01 = 0; 39 | n11 = 0; 40 | nEcn = 0; 41 | for (int n = 0; n < kLossRateHistSize; n++) { 42 | lossRateHist[n] = 0.0f; 43 | ceRateHist[n] = 0.0f; 44 | } 45 | lossRateHistPtr = 0; 46 | } 47 | 48 | void ScreamTx::Statistics::add(uint32_t time_ntp, float rateTx, float rateLost, float rateCe, float rtt, float queueDelay) { 49 | nStatisticsItems++; 50 | const float alpha = 0.98f; 51 | sumRateTx += rateTx; 52 | sumRateLost += rateLost; 53 | sumRateCe += rateCe; 54 | sumRtt += rtt; 55 | minRtt = std::min(minRtt,rtt); 56 | maxRtt = std::max(maxRtt,rtt); 57 | sumQueueDelay += queueDelay; 58 | maxQueueDelay = std::max(maxQueueDelay, queueDelay); 59 | if (time_ntp > kMinTimeForMinMaxStatistics_ntp) { 60 | minRate = std::min(minRate, rateTx); 61 | maxRate = std::max(maxRate, rateTx); 62 | } 63 | if (avgRateTx == 0.0f) { 64 | avgRateTx = rateTx; 65 | avgRtt = rtt; 66 | avgQueueDelay = queueDelay; 67 | } 68 | else { 69 | avgRateTx = alpha * avgRateTx + (1.0f - alpha) * rateTx; 70 | rateLostAcc += rateLost; 71 | rateCeAcc += rateCe; 72 | rateLostN++; 73 | if (rateLostN == 10) { 74 | rateLostAcc /= 10; 75 | rateCeAcc /= 10; 76 | rateLostN = 0; 77 | float lossRate = 0.0f; 78 | float ceRate = 0.0f; 79 | if (rateTx > 0) { 80 | lossRate = rateLostAcc / rateTx * 100.0f; 81 | ceRate = rateCeAcc / rateTx * 100.0f; 82 | } 83 | lossRateHist[lossRateHistPtr] = lossRate; 84 | ceRateHist[lossRateHistPtr] = ceRate; 85 | lossRateHistPtr = (lossRateHistPtr + 1) % kLossRateHistSize; 86 | } 87 | avgRtt = alpha * avgRtt + (1.0f - alpha) * rtt; 88 | avgQueueDelay = alpha * avgQueueDelay + (1.0f - alpha) * queueDelay; 89 | } 90 | lossRate = 0.0f; 91 | ceRate = 0.0f; 92 | for (int n = 0; n < kLossRateHistSize; n++) { 93 | lossRate += lossRateHist[n]; 94 | ceRate += ceRateHist[n]; 95 | } 96 | lossRate /= kLossRateHistSize; 97 | ceRate /= kLossRateHistSize; 98 | lossRateLong = 0.0f; 99 | ceRateLong = 0.0f; 100 | if (sumRateTx > 100000.0f) { 101 | lossRateLong = sumRateLost / sumRateTx * 100.0f; 102 | ceRateLong = sumRateCe / sumRateTx * 100.0f; 103 | } 104 | } 105 | 106 | void ScreamTx::Statistics::addEcn(uint8_t ecn) { 107 | nEcn++; 108 | switch (ecn) { 109 | case 0x00: 110 | n00++; 111 | break; 112 | case 0x02: 113 | n10++; 114 | break; 115 | case 0x01: 116 | n01++; 117 | break; 118 | case 0x03: 119 | n11++; 120 | break; 121 | default: 122 | break; 123 | } 124 | } 125 | 126 | void ScreamTx::Statistics::printFinalSummary() { 127 | printf("\n======================== Summary ==========================\n"); 128 | printf(" Bitrate min/max/avg [kbps] : %5.0f/%5.0f/%5.0f\n",minRate/1000.0f,maxRate/1000.0f, 129 | sumRateTx/nStatisticsItems/1000.0f); 130 | printf(" RTT min/max/avg [s] : %2.3f/%2.3f/%2.3f\n",minRtt,maxRtt,sumRtt/nStatisticsItems); 131 | printf(" Queue delay max/avg [s] : %2.3f/%2.3f\n",maxQueueDelay,sumQueueDelay/nStatisticsItems); 132 | printf(" Packet loss avg [%%] : %4.3f\n", lossRateLong); 133 | int tmp = std::max(1, nEcn); 134 | printf(" ECN/L4S NotECT/ECT(0)/ECT(1)/CE [%%] : %4.1f/%4.1f/%4.1f/%4.1f\n", 135 | 100.0f * float(n00) / tmp, 136 | 100.0f * float(n10) / tmp, 137 | 100.0f * float(n01) / tmp, 138 | 100.0f * float(n11) / tmp); 139 | printf("===========================================================\n"); 140 | } 141 | 142 | void ScreamTx::Statistics::getSummary(float time, char s[]) { 143 | int tmp = std::max(1, nEcn); 144 | sprintf(s, "%s summary %5.1f Transmit rate = %5.0fkbps, PLR = %5.2f%%(%5.2f%%), CE = %5.2f%%(%5.2f%%)[%4.1f%%, %4.1f%%, %4.1f%%, %4.1f%%], RTT = %5.3fs, Queue delay = %5.3fs", 145 | parent->logTag, 146 | time, 147 | avgRateTx / 1000.0f, 148 | lossRate, 149 | lossRateLong, 150 | ceRate, 151 | ceRateLong, 152 | 100.0f * float(n00) / tmp, 153 | 100.0f * float(n10) / tmp, 154 | 100.0f * float(n01) / tmp, 155 | 100.0f * float(n11) / tmp, 156 | avgRtt, 157 | avgQueueDelay); 158 | } 159 | 160 | float ScreamTx::Statistics::getStatisticsItem(StatisticsItem item) { 161 | switch (item) { 162 | case AVG_RATE: 163 | return avgRateTx; 164 | break; 165 | case LOSS_RATE: 166 | return lossRate; 167 | break; 168 | case LOSS_RATE_LONG: 169 | return lossRateLong; 170 | break; 171 | case CE_RATE: 172 | return ceRate; 173 | break; 174 | case CE_RATE_LONG: 175 | return ceRateLong; 176 | break; 177 | case AVG_RTT: 178 | return avgRtt; 179 | break; 180 | case AVG_QUEUE_DELAY: 181 | return avgQueueDelay; 182 | break; 183 | } 184 | return 0.0f; 185 | } 186 | 187 | void ScreamTx::getStatistics(float time, char* s) { 188 | statistics->getSummary(time, s); 189 | } 190 | 191 | float ScreamTx::getStatisticsItem(StatisticsItem item) { 192 | return statistics->getStatisticsItem(item); 193 | } 194 | 195 | void ScreamTx::printFinalSummary() { 196 | statistics->printFinalSummary(); 197 | } 198 | 199 | -------------------------------------------------------------------------------- /code/TxList.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/code/TxList.h -------------------------------------------------------------------------------- /code/VideoEnc.cpp: -------------------------------------------------------------------------------- 1 | #include "VideoEnc.h" 2 | #include "RtpQueue.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | static const int kRtpOverHead = 12; 12 | 13 | uint32_t SSRC = 1; 14 | VideoEnc::VideoEnc(RtpQueue* rtpQueue_, float frameRate_, char *fname, int ixOffset_, float sluggishness_) { 15 | rtpQueue = rtpQueue_; 16 | frameRate = frameRate_; 17 | ix = ixOffset_; 18 | nFrames = 0; 19 | seqNr = 0; 20 | timeStamp = 0; 21 | nominalBitrate = 0.0; 22 | sluggishness = sluggishness_; 23 | FILE *fp = fopen(fname,"r"); 24 | char s[100]; 25 | float sum = 0.0; 26 | bytes = 0.0f; 27 | while (fgets(s,99,fp)) { 28 | if (nFrames < MAX_FRAMES - 1) { 29 | float x = atof(s); 30 | frameSize[nFrames] = x; 31 | nFrames++; 32 | sum += x; 33 | } 34 | } 35 | float t = nFrames / frameRate; 36 | nominalBitrate = sum * 8 / t; 37 | fclose(fp); 38 | } 39 | 40 | void VideoEnc::setTargetBitrate(float targetBitrate_) { 41 | targetBitrate = targetBitrate_; 42 | } 43 | 44 | int VideoEnc::encode(float time) { 45 | 46 | int rtpBytes = 0; 47 | char rtpPacket[2000]; 48 | float tmp = (int)(frameSize[ix] / nominalBitrate * targetBitrate); 49 | if (bytes > 0) 50 | bytes = bytes * (sluggishness)+(1.0 - sluggishness) * tmp; 51 | else 52 | bytes = tmp; 53 | 54 | int tmp2 = (int) bytes; 55 | //nominalBitrate = 0.95*nominalBitrate + 0.05*frameSize[ix] * frameRate * 8; 56 | ix++; if (ix == nFrames) ix = 0; 57 | while (tmp2 > 0) { 58 | int rtpSize = std::min(mss, tmp2); 59 | bool isMarker = rtpSize < mss; 60 | tmp2 -= rtpSize; 61 | rtpSize += kRtpOverHead; 62 | rtpBytes += rtpSize; 63 | rtpQueue->push(rtpPacket, rtpSize, SSRC, seqNr, isMarker, time, timeStamp); 64 | seqNr++; 65 | timeStamp = (unsigned long)(time * 90000); 66 | } 67 | rtpQueue->setSizeOfLastFrame(rtpBytes); 68 | return rtpBytes; 69 | } 70 | 71 | -------------------------------------------------------------------------------- /code/VideoEnc.h: -------------------------------------------------------------------------------- 1 | #ifndef VIDEO_ENC 2 | #define VIDEO_ENC 3 | 4 | class RtpQueue; 5 | #define MAX_FRAMES 10000 6 | class VideoEnc { 7 | public: 8 | VideoEnc(RtpQueue* rtpQueue, float frameRate, char *fname, int ixOffset=0, float sluggishness = 0.0); 9 | 10 | int encode(float time); 11 | 12 | void setTargetBitrate(float targetBitrate); 13 | 14 | void setMss(int mss_) { 15 | mss = mss_; 16 | } 17 | 18 | RtpQueue* rtpQueue; 19 | float frameSize[MAX_FRAMES]; 20 | int nFrames; 21 | float targetBitrate; 22 | float frameRate; 23 | float nominalBitrate; 24 | unsigned int seqNr; 25 | unsigned long timeStamp; 26 | int ix; 27 | int mss; 28 | 29 | float sluggishness; 30 | float bytes; 31 | }; 32 | 33 | 34 | #endif -------------------------------------------------------------------------------- /code/scream_01.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {995F8DF3-7BE9-4B48-89EA-4F64046D68C2} 15 | Win32Proj 16 | scream_01 17 | 10.0 18 | 19 | 20 | 21 | Application 22 | true 23 | Unicode 24 | v143 25 | 26 | 27 | Application 28 | false 29 | true 30 | Unicode 31 | v143 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | false 45 | 46 | 47 | false 48 | 49 | 50 | 51 | NotUsing 52 | Level3 53 | Disabled 54 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);IGNORE_PACKET 55 | %(AdditionalIncludeDirectories) 56 | 57 | 58 | Console 59 | true 60 | %(AdditionalLibraryDirectories) 61 | %(AdditionalDependencies);Ws2_32.lib 62 | 63 | 64 | 65 | 66 | Level3 67 | NotUsing 68 | MaxSpeed 69 | true 70 | true 71 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);IGNORE_PACKET 72 | %(AdditionalIncludeDirectories) 73 | 74 | 75 | Console 76 | true 77 | true 78 | true 79 | %(AdditionalLibraryDirectories) 80 | %(AdditionalDependencies);Ws2_32.lib 81 | true 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /code/scream_01.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /code/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // scream_01.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /code/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #ifdef _WIN32 9 | #include "targetver.h" 10 | #include 11 | #include 12 | #else 13 | #include "unistd.h" // for sleep 14 | #endif 15 | 16 | // TODO: reference additional headers your program requires here 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | -------------------------------------------------------------------------------- /code/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /code/wrapper_lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # source files 2 | 3 | #set(CMAKE_VERBOSE_MAKEFILE ON) 4 | 5 | set(BUILD_SHARED_LIBS on) 6 | 7 | SET(HEADERS 8 | ../ScreamTx.h 9 | ../RtpQueue.h 10 | ) 11 | 12 | SET(SRCS 13 | ../RtpQueue.cpp 14 | ../ScreamTx.cpp 15 | ../ScreamV2Tx.cpp 16 | ../ScreamV2TxStream.cpp 17 | screamtxbw_plugin_wrapper.cpp 18 | screamtx_plugin_wrapper.cpp 19 | ) 20 | 21 | set(CMAKE_BUILD_TYPE Debug) 22 | 23 | if(BUILD_SHARED_LIBS) 24 | set(CMAKE_CXX_FLAGS " -DV2 -I.. ${CMAKE_CXX_FLAGS_INIT} ") 25 | add_library(scream SHARED ${SRCS}) 26 | 27 | else() 28 | 29 | set(CMAKE_CXX_FLAGS " -DV2 -g -I .. ${CMAKE_CXX_FLAGS_INIT} -fPIC") 30 | add_library(scream STATIC ${SRCS}) 31 | endif() 32 | 33 | 34 | INCLUDE_DIRECTORIES( 35 | ${screamIncludes} 36 | ) 37 | -------------------------------------------------------------------------------- /code/wrapper_lib/meson.build: -------------------------------------------------------------------------------- 1 | project('scream', 'cpp', version : '0.0.1', license : 'BSD') 2 | add_project_arguments('-DV2', language : 'cpp') 3 | 4 | cc = meson.get_compiler('cpp') 5 | 6 | is_window = target_machine.system() == 'windows' 7 | sources = [ 8 | 'screamtx_plugin_wrapper.cpp', 9 | '../RtpQueue.cpp', 10 | '../ScreamTx.cpp', 11 | '../ScreamV2Tx.cpp', 12 | '../ScreamV2TxStream.cpp', 13 | ] 14 | 15 | incdir = include_directories('..') 16 | 17 | threads_dep = dependency('threads') 18 | winsock_dep = cc.find_library('ws2_32', required: is_window) 19 | 20 | library('scream', 21 | sources : sources, 22 | include_directories : incdir, 23 | dependencies : [threads_dep, winsock_dep], 24 | install : true 25 | ) 26 | -------------------------------------------------------------------------------- /gstscream/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /gstscream/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gstscream" 3 | version = "0.6.0" 4 | authors = ["Jacob Teplitsky"] 5 | repository = "https://github.com/EricssonResearch/scream.git" 6 | license = "BSD 2-clause" 7 | edition = "2021" 8 | description = "Rust Gstscream Scream Plugin" 9 | 10 | [dependencies] 11 | gst = { package = "gstreamer", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git" } 12 | gst-base = { package = "gstreamer-base", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git" } 13 | gst-video = { package = "gstreamer-video", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git" } 14 | gst-sys = { package = "gstreamer-sys", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git" } 15 | gst-rtp = { package = "gstreamer-rtp", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git" } 16 | 17 | once_cell = "1.0" 18 | array-init = "0.1.1" 19 | hashbrown="0.9.0" 20 | lazy_static = "1.3.0" 21 | libc = "0.2.68" 22 | failure = "0.1" 23 | gtypes = "0.2.0" 24 | chrono = "0.4" 25 | clap = { version = "4.5.11", features=["env","derive"] } 26 | 27 | [lib] 28 | name = "gstscream" 29 | crate-type = ["cdylib", "rlib", "staticlib"] 30 | path = "src/lib.rs" 31 | 32 | [[bin]] 33 | name="scream_sender" 34 | path="src/sender.rs" 35 | 36 | [[bin]] 37 | name="scream_receiver" 38 | path="src/receiver.rs" 39 | 40 | [build-dependencies] 41 | gst-plugin-version-helper = { git = "https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git" } 42 | 43 | [features] 44 | screamrx-only = [] 45 | ecn-enabled = [] 46 | screamtxbw-enabled = [] 47 | 48 | default = [] 49 | -------------------------------------------------------------------------------- /gstscream/README.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | [rust](https://doc.rust-lang.org/book/ch01-01-installation.html#installing-rustup-on-linux-or-macos) 4 | 5 | [gstreamer](https://gstreamer.freedesktop.org/documentation/installing/on-linux.html?gi-language=c) 6 | 7 | # Building gstscream and sample applications 8 | Should be possible to build and run on Windows (not tested) 9 | However SCReAM BW can't be built for Windows. 10 | Therefore modify build.sh to remove --features screamtxbw-enabled 11 | ```bash 12 | ./scripts/build.sh 13 | ``` 14 | 15 | # Environment Variables are set in script/env.sh 16 | ```bash 17 | export SENDER_STATS_TIMER=500 # default 1000 ms 18 | export SENDER_STATS_FILE_NAME="xxx.csv" # default sender_scream_stats.csv 19 | ``` 20 | See script/env.sh to set 21 | ECN_ENABLED, USE_SCREAM, SENDER_IP, RECEIVER_IP, ENCODER, DECODER, ENC_ID 22 | 23 | # Tuning Linux system 24 | ```bash 25 | sudo ./scripts/sysctl.sh 26 | ``` 27 | # Running remote rendering test applications 28 | ```bash 29 | # first window 30 | ./scripts/receiver.sh 31 | # second window 32 | ./scripts/sender.sh 33 | ``` 34 | # Running remote rendering test applications with 3 video screams 35 | ```bash 36 | # first window 37 | ./scripts/receiver_3.sh 38 | # second window 39 | ./scripts/sender_3.sh 40 | ``` 41 | # Running SCReAM BW test applications 42 | ```bash 43 | # first window 44 | ./scripts/receiver_bw.sh 45 | # second window 46 | ./scripts/sender_bw.sh 47 | ``` 48 | # To use unattended machine: 49 | ```shell 50 | #ssh-1 window 51 | systemctl isolate multi-user.target 52 | sudo Xorg 53 | 54 | #ssh-2 window 55 | export DISPLAY=:0 56 | ./receiver_run.sh 57 | #ssh-3 window 58 | export DISPLAY=:0 59 | ./sender_run.sh 60 | ``` 61 | 62 | # __Be aware of legal implications of using software build with gpl=enabled__ 63 | 64 | # Modifying gstreamer to use L4S 65 | Based on patch [https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2717] 66 | ```bash 67 | cd scream/.. 68 | git clone https://gitlab.freedesktop.org/gstreamer/gstreamer.git 69 | cd gstreamer 70 | meson setup --prefix=/path/to/install/prefix build 71 | 72 | # to build x264, you might want to add to meson setup 73 | -Dgst-plugins-ugly:x264=enabled -Dgpl=enabled 74 | 75 | meson compile -C build 76 | patch -p1 < scream/gstscream/udp_ecn_diff.txt 77 | meson compile -C build 78 | meson install -C build 79 | ``` 80 | # Build and run with modified gstreamer 81 | ## Modify scripts/env.sh 82 | set ECN_ENABLED=1 83 | Make sure that MY_GST_INSTALL points to the correct install directory. 84 | ## Build 85 | ./scripts/build.sh 86 | ## Run 87 | Use receiver and sender scripts described earlier 88 | Receiver should print once "screamrx/imp.rs ecn-enabled" 89 | If export GST_DEBUG="screamrx:7" is set, the following trace log should be displayed: 90 | screamrx src/screamrx/imp.rs ..... ecn_ce 1 91 | 92 | # Issues 93 | [Issues with using tc](https://github.com/EricssonResearch/scream/issues/44#issuecomment-1112448356 ) 94 | 95 | # Logging 96 | File `gstscream/src/sender_util.rs` provides an example of how to retrieve periodic statistics 97 | from the SCReAM library into a `.csv` file. Below is an explanation for some of the important 98 | fields: 99 | 100 | * `time-ns` Time in ns of getting log record. 101 | * `queueDelay` The estimated network queue delay, i.e time a packet is read from 102 | internal RTP queue and time a packer read by receiver screamrx element. It is "estimated" 103 | because the clocks on the sender and receiver sides are not synchronized. (In sec) 104 | 105 | * `queueDelayMax` The maximum value of `queueDelay` in seconds, which is reset after 106 | printing logs. 107 | 108 | * `queueDelayMin` The minimum value of `queueDelay` in seconds, which is reset after 109 | printing logs. Together, queueDelayXXX fields indicate size of jitter. 110 | 111 | * `rtpQueueDelay` The duration for which RTP packets are kept in the RTP queue. 112 | If `rtpQueueDelay` exceeds a hardcoded threshold the RTP queue 113 | is completely emptied. Number of cleared packets added to Counter packetetsRtpCleared 114 | 115 | * `acketsLost` Unacked packets outside window are considered lost. They might be received by receiver. 116 | Used to calculate "targetBitrate" 117 | 118 | * `rateRtp vs. rateTransmitted` `rateRtp` is the moving avr bitrate including RTP header 119 | of packet read by screamtx element, while `rateTransmitted` is the transmitted bitrate. These 120 | can differ if RTP packets are queued on the sender side. (In kbit/sec) 121 | 122 | 123 | * `rtpQueueBytes and rtpQueueSize` These represent bytes in the RTP queue and the number of packets, 124 | respectively, at the time of logging. Not average. 125 | 126 | * `targetBitrate` SCReAM recommended to encoder at the time of logging. Not avr. 127 | 128 | * `bytesInFlightLog` Max of bytesInFlight for time between two log records. 129 | 130 | * `Cwnd` Congestion Window the amount of data that can be sent into the network before needing an acknowledgment. in Bytes 131 | 132 | * `srtt` Smoothed Round-Trip Time. a measure to estimate the round-trip time(RTT) in seconds 133 | 134 | # building graphs in send_graphs directory 135 | ```bash 136 | ./scripts/screamtx_stats.py sender_scream_stats_0.csv 137 | ``` 138 | # Arguments: 139 | Scream has many parameters kept for historical reasons or for development. Current SCReAM is self 140 | adjusting with default parameters. 141 | Here are few that you might want to set 142 | * `-minrate, -maxrate, initrate` in kbit/sec 143 | If encoder you are using uses bit/sec as bitrate property, you'll have to convert in your code when you set encoder 144 | bitrate property. 145 | * `force_idr` If packet loss is detected, gstscream, will send :UpstreamForceKeyUnitEvent, no more 146 | often than every 100ms 147 | There is alternative way to receiver application to send upstream GstForceKeyUnit event. In 148 | this case -force_idr should not be set 149 | 150 | -------------------------------------------------------------------------------- /gstscream/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | gst_plugin_version_helper::info(); 3 | } 4 | -------------------------------------------------------------------------------- /gstscream/scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | SCRIPT_PATH=$(realpath $0) 3 | SCRIPT_DIR=$(dirname $SCRIPT_PATH) 4 | source $SCRIPT_DIR/env.sh 5 | SCREAMLIB_DIR=$SCRIPT_DIR/../../code/wrapper_lib 6 | cd $SCREAMLIB_DIR; cmake .; make 7 | cd $SCRIPT_DIR 8 | export RUSTFLAGS="$RUSTFLAGS -L$SCREAMLIB_DIR" 9 | if (($ECN_ENABLED == 1)); then 10 | cargo build --features ecn-enabled,screamtxbw-enabled 11 | cargo clippy --features ecn-enabled,screamtxbw-enabled 12 | else 13 | cargo build --features screamtxbw-enabled 14 | cargo clippy --features screamtxbw-enabled 15 | fi 16 | 17 | -------------------------------------------------------------------------------- /gstscream/scripts/env.sh: -------------------------------------------------------------------------------- 1 | export ECN_ENABLED=0 2 | if (($ECN_ENABLED == 1)); then 3 | export SET_ECN="set-ecn=1" 4 | export SCREAMTX_PARAM_ECT="-ect 1" 5 | export RETRIEVE_ECN="retrieve-ecn=true" 6 | MY_GST_INSTALL=$(readlink -f $SCRIPT_DIR/../../../udp_gstreamer/install) 7 | echo "MY_GST_INSTALL=$MY_GST_INSTALL" 8 | export GST_PLUGIN_PATH=$MY_GST_INSTALL/lib/x86_64-linux-gnu 9 | export GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$MY_GST_INSTALL/lib/x86_64-linux-gnu/gstreamer-1.0 10 | export GST_PLUGIN_PATH=$GST_PLUGIN_PATH:/usr/lib/x86_64-linux-gnu/gstreamer-1.0 11 | 12 | export LD_LIBRARY_PATH=$MY_GST_INSTALL/lib/x86_64-linux-gnu 13 | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MY_GST_INSTALL/lib/x86_64-linux-gnu/gstreamer-1.0 14 | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu/gstreamer-1.0 15 | 16 | export PATH=$MY_GST_INSTALL/bin:$PATH 17 | export PKG_CONFIG_PATH=$MY_GST_INSTALL/lib/x86_64-linux-gnu/pkgconfig 18 | export PYTHONPATH=${PYTHONPATH}:$MY_GST_INSTALL/lib/python3/site-packages/ 19 | LP=$(pkg-config --libs-only-L gstreamer-1.0 ) 20 | export RUSTFLAGS="$LP $RUSTFLAGS" 21 | fi 22 | 23 | SCREAMLIB_DIR=$SCRIPT_DIR/../../code/wrapper_lib 24 | SCREAM_TARGET_DIR=$SCRIPT_DIR/../target/debug/ 25 | export GST_PLUGIN_PATH=$SCREAM_TARGET_DIR:$GST_PLUGIN_PATH 26 | export LD_LIBRARY_PATH=$SCREAMLIB_DIR:$LD_LIBRARY_PATH 27 | 28 | echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" 29 | echo "GST_PLUGIN_PATH=$GST_PLUGIN_PATH" 30 | 31 | export ENC_ID=264 32 | 33 | SENDER_IP=127.0.0.2 34 | RECEIVER_IP=127.0.0.1 35 | 36 | PORT0_RTP=30112 37 | PORT0_RTCP=30113 38 | 39 | PORT1_RTP=30114 40 | PORT1_RTCP=30115 41 | 42 | PORT2_RTP=30116 43 | PORT2_RTCP=30117 44 | 45 | #ENCODER="x${ENC_ID}enc speed-preset=ultrafast tune=zerolatency key-int-max=10000 " 46 | #only for x264: 47 | ENCODER="x264enc speed-preset=ultrafast tune=fastdecode+zerolatency key-int-max=10000 " 48 | 49 | #ENCODER="nvh${ENC_ID}enc zerolatency=true preset=low-latency-hq rc-mode=cbr-ld-hq gop-size=-1 " 50 | 51 | DECODER=avdec_h${ENC_ID} 52 | #DECODER=nvh${ENC_ID}dec 53 | # 54 | 55 | USE_SCREAM=1 56 | #if you set USE_SCREAM=0, modify key-int-max or gop-size in ENCODER above to periodically resend I frames 57 | -------------------------------------------------------------------------------- /gstscream/scripts/receiver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | SCRIPT_PATH=$(realpath $0) 3 | SCRIPT_DIR=$(dirname $SCRIPT_PATH) 4 | source $SCRIPT_DIR/env.sh 5 | 6 | QUEUE="queue max-size-buffers=2 max-size-bytes=0 max-size-time=0" 7 | 8 | if (($USE_SCREAM == 1)); then 9 | SCREAMRX0="! screamrx name=screamrx0 screamrx0.src " 10 | SCREAMRX0_RTCP="screamrx0.rtcp_src ! f0." 11 | else 12 | SCREAMRX0="" 13 | SCREAMRX0_RTCP="" 14 | fi 15 | 16 | VIDEOSINK="videoconvert ! fpsdisplaysink video-sink=\"ximagesink\"" 17 | #VIDEOSINK="glupload ! glcolorconvert ! fpsdisplaysink video-sink=\"glimagesinkelement\"" 18 | #VIDEOSINK="fakesink" 19 | 20 | export RECVPIPELINE="rtpbin latency=10 name=r \ 21 | udpsrc port=$PORT0_RTP address=$RECEIVER_IP $RETRIEVE_ECN ! \ 22 | queue $SCREAMRX0 ! application/x-rtp, media=video, encoding-name=H${ENC_ID}, clock-rate=90000 ! r.recv_rtp_sink_0 r. ! rtph${ENC_ID}depay ! h${ENC_ID}parse ! $DECODER name=videodecoder0 ! $QUEUE ! $VIDEOSINK \ 23 | r.send_rtcp_src_0 ! funnel name=f0 ! queue ! udpsink host=$SENDER_IP port=$PORT0_RTCP sync=false async=false \ 24 | $SCREAMRX0_RTCP udpsrc port=$PORT0_RTCP ! r.recv_rtcp_sink_0 \ 25 | " 26 | 27 | export GST_DEBUG="2,screamrx:2" 28 | killall -9 scream_receiver 29 | $SCREAM_TARGET_DIR/scream_receiver 30 | -------------------------------------------------------------------------------- /gstscream/scripts/receiver_3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | SCRIPT_PATH=$(realpath $0) 3 | SCRIPT_DIR=$(dirname $SCRIPT_PATH) 4 | source $SCRIPT_DIR/env.sh 5 | 6 | QUEUE="queue max-size-buffers=2 max-size-bytes=0 max-size-time=0" 7 | 8 | if (($USE_SCREAM == 1)); then 9 | SCREAMRX0="! screamrx name=screamrx0 screamrx0.src " 10 | SCREAMRX0_RTCP="screamrx0.rtcp_src ! f0." 11 | # 12 | SCREAMRX1="! screamrx name=screamrx1 screamrx1.src " 13 | SCREAMRX1_RTCP="screamrx1.rtcp_src ! f1." 14 | # 15 | SCREAMRX2="! screamrx name=screamrx2 screamrx2.src " 16 | SCREAMRX2_RTCP="screamrx2.rtcp_src ! f2." 17 | else 18 | SCREAMRX0="" 19 | SCREAMRX0_RTCP="" 20 | SCREAMRX1="" 21 | SCREAMRX1_RTCP="" 22 | SCREAMRX2="" 23 | SCREAMRX2_RTCP="" 24 | fi 25 | 26 | DECODER=avdec_h${ENC_ID} 27 | #DECODER=nvh${ENC_ID}dec 28 | VIDEOSINK="videoconvert ! fpsdisplaysink video-sink=\"ximagesink\"" 29 | #VIDEOSINK="fakesink" 30 | 31 | export RECVPIPELINE="rtpbin latency=10 name=r \ 32 | udpsrc port=$PORT0_RTP address=$RECEIVER_IP $RETRIEVE_ECN ! \ 33 | queue $SCREAMRX0 ! application/x-rtp, media=video, encoding-name=H${ENC_ID}, clock-rate=90000 ! r.recv_rtp_sink_0 r. ! rtph${ENC_ID}depay ! h${ENC_ID}parse ! $DECODER name=videodecoder0 ! $QUEUE ! $VIDEOSINK \ 34 | r.send_rtcp_src_0 ! funnel name=f0 ! queue ! udpsink host=$SENDER_IP port=$PORT0_RTCP sync=false async=false \ 35 | $SCREAMRX0_RTCP udpsrc port=$PORT0_RTCP ! r.recv_rtcp_sink_0 \ 36 | \ 37 | udpsrc port=$PORT1_RTP address=$RECEIVER_IP $RETRIEVE_ECN ! \ 38 | queue $SCREAMRX1 ! application/x-rtp, media=video, encoding-name=H${ENC_ID}, clock-rate=90000 ! r.recv_rtp_sink_1 r. ! rtph${ENC_ID}depay ! h${ENC_ID}parse ! $DECODER name=videodecoder1 ! $QUEUE ! $VIDEOSINK \ 39 | r.send_rtcp_src_1 ! funnel name=f1 ! queue ! udpsink host=$SENDER_IP port=$PORT1_RTCP sync=false async=false \ 40 | $SCREAMRX1_RTCP udpsrc port=$PORT1_RTCP ! r.recv_rtcp_sink_1 \ 41 | \ 42 | udpsrc port=$PORT2_RTP address=$RECEIVER_IP $RETRIEVE_ECN ! \ 43 | queue $SCREAMRX2 ! application/x-rtp, media=video, encoding-name=H${ENC_ID}, clock-rate=90000 ! r.recv_rtp_sink_2 r. ! rtph${ENC_ID}depay ! h${ENC_ID}parse ! $DECODER name=videodecoder2 ! $QUEUE ! $VIDEOSINK \ 44 | r.send_rtcp_src_2 ! funnel name=f2 ! queue ! udpsink host=$SENDER_IP port=$PORT2_RTCP sync=false async=false \ 45 | $SCREAMRX2_RTCP udpsrc port=$PORT2_RTCP ! r.recv_rtcp_sink_2 \ 46 | " 47 | 48 | export GST_DEBUG="screamrx:2" 49 | killall -9 scream_receiver 50 | $SCREAM_TARGET_DIR/scream_receiver 51 | -------------------------------------------------------------------------------- /gstscream/scripts/receiver_bw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | SCRIPT_PATH=$(realpath $0) 3 | SCRIPT_DIR=$(dirname $SCRIPT_PATH) 4 | source $SCRIPT_DIR/env.sh 5 | 6 | export RECVPIPELINE="rtpbin latency=10 name=r udpsrc port=$PORT0_RTP address=$RECEIVER_IP ! screamrx name=screamrx screamrx.src ! fakesink r.send_rtcp_src_0 ! funnel name=f ! udpsink host=$SENDER_IP port=$PORT0_RTCP sync=false async=false screamrx.rtcp_src ! f. " 7 | 8 | killall -9 scream_receiver 9 | $SCREAM_TARGET_DIR/scream_receiver 10 | -------------------------------------------------------------------------------- /gstscream/scripts/screamtx_stats.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import matplotlib.pyplot as plt 3 | import pandas as pd 4 | import sys 5 | import pathlib 6 | 7 | input_file = sys.argv[1] 8 | 9 | df = pd.read_csv(input_file) 10 | 11 | graph_dir = 'send_graphs/' 12 | 13 | pathlib.Path(graph_dir).mkdir(parents=True, exist_ok=True) 14 | 15 | df['time-sec'] = df['time-ns'] / 1e9 16 | 17 | df['packetsLostRate'] = df['packetsLost'].diff().fillna(0) / df['time-sec'].diff().fillna(1) 18 | 19 | def plot_queue_delay(ax): 20 | ax.plot(df['time-sec'], df['queueDelay'], label='Queue Delay') 21 | ax.plot(df['time-sec'], df['queueDelayMax'], label='Queue Delay Max', linestyle='--') 22 | ax.plot(df['time-sec'], df['queueDelayMinAvg'], label='Queue Delay Min Avg', linestyle='--') 23 | ax.set_xlabel('Time (seconds)') 24 | ax.set_ylabel('Delay (seconds)') 25 | ax.set_title('Queue Delay over Time') 26 | ax.legend() 27 | ax.grid(True) 28 | 29 | def plot_packets_loss_rate(ax): 30 | ax.plot(df['time-sec'], df['packetsLostRate'], label='Packet Loss Rate', color='green') 31 | ax.set_xlabel('Time (seconds)') 32 | ax.set_ylabel('Packet Loss Rate') 33 | ax.set_title('Packet Loss Rate over Time') 34 | ax.grid(True) 35 | 36 | def plot_bitrates(ax): 37 | ax.plot(df['time-sec'], df['rateRtp'], label='Rate RTP', color='blue') 38 | ax.plot(df['time-sec'], df['rateTransmitted'], label='Rate Transmitted', color='orange') 39 | ax.plot(df['time-sec'], df['rateAcked'], label='Rate Acked', color='purple') 40 | ax.plot(df['time-sec'], df['targetBitrate'], label='Target Bitrate', color='brown') 41 | ax.set_xlabel('Time (seconds)') 42 | ax.set_ylabel('Bitrate (kbit/sec)') 43 | ax.set_title('Comparison of Bitrates over Time') 44 | ax.legend() 45 | ax.grid(True) 46 | 47 | def plot_cwnd_srtt(ax): 48 | ax.plot(df['time-sec'], df['cwnd'], label='Congestion Window', color='tab:red') 49 | ax.set_xlabel('Time (seconds)') 50 | ax.set_ylabel('Congestion Window (Bytes)', color='tab:red') 51 | ax.tick_params(axis='y', labelcolor='tab:red') 52 | ax2 = ax.twinx() 53 | ax2.plot(df['time-sec'], df['sRtt'], label='Smoothed RTT', color='tab:blue') 54 | ax2.set_ylabel('SRTT (seconds)', color='tab:blue') 55 | ax2.tick_params(axis='y', labelcolor='tab:blue') 56 | ax.set_title('Congestion Window and SRTT over Time') 57 | 58 | fig_queue_delay, ax_queue_delay = plt.subplots(figsize=(12, 6)) 59 | plot_queue_delay(ax_queue_delay) 60 | fig_queue_delay.tight_layout() 61 | fig_queue_delay.savefig(graph_dir + 'queue_delay_plot.png', dpi=300) 62 | 63 | fig_packets_loss_rate, ax_packets_loss_rate = plt.subplots(figsize=(12, 6)) 64 | plot_packets_loss_rate(ax_packets_loss_rate) 65 | fig_packets_loss_rate.tight_layout() 66 | fig_packets_loss_rate.savefig(graph_dir + 'packets_loss_rate_plot.png', dpi=300) 67 | 68 | fig_bitrate, ax_bitrate = plt.subplots(figsize=(12, 6)) 69 | plot_bitrates(ax_bitrate) 70 | fig_bitrate.tight_layout() 71 | fig_bitrate.savefig(graph_dir + 'bitrate_plot.png', dpi=300) 72 | 73 | fig_cwnd_srtt, ax_cwnd_srtt = plt.subplots(figsize=(12, 6)) 74 | plot_cwnd_srtt(ax_cwnd_srtt) 75 | fig_cwnd_srtt.tight_layout() 76 | fig_cwnd_srtt.savefig(graph_dir + 'cwnd_srtt_plot.png', dpi=300) 77 | 78 | fig_combined_vertical, axs_combined_vertical = plt.subplots(4, figsize=(12, 24)) 79 | plot_queue_delay(axs_combined_vertical[0]) 80 | plot_packets_loss_rate(axs_combined_vertical[1]) 81 | plot_bitrates(axs_combined_vertical[2]) 82 | plot_cwnd_srtt(axs_combined_vertical[3]) 83 | fig_combined_vertical.tight_layout() 84 | fig_combined_vertical.subplots_adjust(hspace=0.5) 85 | fig_combined_vertical.savefig(graph_dir + 'combined_plot_vertical.png', dpi=300) 86 | 87 | fig_combined_grid, axs_combined_grid = plt.subplots(2, 2, figsize=(16, 12)) 88 | plot_queue_delay(axs_combined_grid[0, 0]) 89 | plot_packets_loss_rate(axs_combined_grid[0, 1]) 90 | plot_bitrates(axs_combined_grid[1, 0]) 91 | plot_cwnd_srtt(axs_combined_grid[1, 1]) 92 | fig_combined_grid.tight_layout() 93 | fig_combined_grid.subplots_adjust(hspace=0.5, wspace=0.3) 94 | fig_combined_grid.savefig(graph_dir + 'combined_plot_grid.png', dpi=300) 95 | -------------------------------------------------------------------------------- /gstscream/scripts/sender.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | SCRIPT_PATH=$(realpath $0) 3 | export SCRIPT_DIR=$(dirname $SCRIPT_PATH) 4 | source $SCRIPT_DIR/env.sh 5 | 6 | INIT_ENC_BITRATE=5000 7 | 8 | if (($USE_SCREAM == 1)); then 9 | INIT_ENC_BITRATE=500 10 | #NOSUMMARY=" -nosummary" 11 | # 12 | 13 | SCREAMTX0="queue ! screamtx name=\"screamtx0\" params=\"$NOSUMMARY -forceidr $SCREAMTX_PARAM_ECT -initrate $INIT_ENC_BITRATE -minrate 200 -maxrate 8000\" ! queue !" 14 | SCREAMTX0_RTCP="screamtx0.rtcp_sink screamtx0.rtcp_src !" 15 | else 16 | SCREAMTX0="" 17 | SCREAMTX0_RTCP="" 18 | fi 19 | 20 | VIDEOSRC="videotestsrc is-live=true pattern=snow ! video/x-raw,format=I420,width=1280,height=720,framerate=50/1" 21 | 22 | export SENDPIPELINE="rtpbin name=r \ 23 | $VIDEOSRC ! $ENCODER name=encoder0 bitrate=$INIT_ENC_BITRATE ! rtph${ENC_ID}pay config-interval=-1 ! $SCREAMTX0 r.send_rtp_sink_0 r.send_rtp_src_0 ! udpsink host=$RECEIVER_IP port=$PORT0_RTP sync=false $SET_ECN \ 24 | udpsrc port=$PORT0_RTCP address=$SENDER_IP ! queue ! $SCREAMTX0_RTCP r.recv_rtcp_sink_0 \ 25 | r.send_rtcp_src_0 ! udpsink host=$RECEIVER_IP port=$PORT0_RTCP sync=false async=false \ 26 | " 27 | export GST_DEBUG="2,screamtx:2" 28 | killall -9 scream_sender 29 | $SCREAM_TARGET_DIR/scream_sender --verbose 30 | -------------------------------------------------------------------------------- /gstscream/scripts/sender_3.sh: -------------------------------------------------------------------------------- 1 | SCRIPT_PATH=$(realpath $0) 2 | SCRIPT_DIR=$(dirname $SCRIPT_PATH) 3 | source $SCRIPT_DIR/env.sh 4 | 5 | INIT_ENC_BITRATE=5000 6 | 7 | #needed for lo and other low latency links 8 | NETSIM="netsim min-delay=10 !" 9 | 10 | if (($USE_SCREAM == 1)); then 11 | INIT_ENC_BITRATE=500 12 | #NOSUMMARY=" -nosummary" 13 | # 14 | SCREAMTX0="queue ! screamtx name=\"screamtx0\" params=\"$NOSUMMARY -forceidr -priority 1.0 $SCREAMTX_PARAM_ECT -initrate $INIT_ENC_BITRATE -minrate 200 -maxrate 8000\" ! queue !" 15 | SCREAMTX0_RTCP="screamtx0.rtcp_sink screamtx0.rtcp_src !" 16 | # 17 | SCREAMTX1="queue ! screamtx name=\"screamtx1\" params=\"$NOSUMMARY -forceidr -priority 0.5 $SCREAMTX_PARAM_ECT -initrate $INIT_ENC_BITRATE -minrate 200 -maxrate 15000\" ! queue !" 18 | SCREAMTX1_RTCP="screamtx1.rtcp_sink screamtx1.rtcp_src !" 19 | # 20 | SCREAMTX2="queue ! screamtx name=\"screamtx2\" params=\"$NOSUMMARY -forceidr -priority 0.2 $SCREAMTX_PARAM_ECT -initrate $INIT_ENC_BITRATE -minrate 200 -maxrate 1000\" ! queue !" 21 | SCREAMTX2_RTCP="screamtx2.rtcp_sink screamtx2.rtcp_src !" 22 | else 23 | SCREAMTX0="" 24 | SCREAMTX0_RTCP="" 25 | SCREAMTX1="" 26 | SCREAMTX1_RTCP="" 27 | SCREAMTX2="" 28 | SCREAMTX2_RTCP="" 29 | fi 30 | 31 | 32 | VIDEOSRC="videotestsrc is-live=true pattern=snow ! video/x-raw,format=I420,width=1280,height=720,framerate=50/1" 33 | 34 | export SENDPIPELINE="rtpbin name=r \ 35 | $VIDEOSRC ! $ENCODER name=encoder0 bitrate=$INIT_ENC_BITRATE ! rtph${ENC_ID}pay config-interval=-1 ! $SCREAMTX0 r.send_rtp_sink_0 r.send_rtp_src_0 ! $NETSIM udpsink host=$RECEIVER_IP port=$PORT0_RTP sync=false $SET_ECN \ 36 | udpsrc port=$PORT0_RTCP address=$SENDER_IP ! queue ! $SCREAMTX0_RTCP r.recv_rtcp_sink_0 \ 37 | r.send_rtcp_src_0 ! udpsink host=$RECEIVER_IP port=$PORT0_RTCP sync=false async=false \ 38 | \ 39 | $VIDEOSRC ! $ENCODER name=encoder1 bitrate=$INIT_ENC_BITRATE ! rtph${ENC_ID}pay config-interval=-1 ! $SCREAMTX1 r.send_rtp_sink_1 r.send_rtp_src_1 ! $NETSIM udpsink host=$RECEIVER_IP port=$PORT1_RTP sync=false $SET_ECN \ 40 | udpsrc port=$PORT1_RTCP address=$SENDER_IP ! queue ! $SCREAMTX1_RTCP r.recv_rtcp_sink_1 \ 41 | r.send_rtcp_src_1 ! udpsink host=$RECEIVER_IP port=$PORT1_RTCP sync=false async=false \ 42 | \ 43 | $VIDEOSRC ! $ENCODER name=encoder2 bitrate=$INIT_ENC_BITRATE ! rtph${ENC_ID}pay config-interval=-1 ! $SCREAMTX2 r.send_rtp_sink_2 r.send_rtp_src_2 ! $NETSIM udpsink host=$RECEIVER_IP port=$PORT2_RTP sync=false $SET_ECN \ 44 | udpsrc port=$PORT2_RTCP address=$SENDER_IP ! queue ! $SCREAMTX2_RTCP r.recv_rtcp_sink_2 \ 45 | r.send_rtcp_src_1 ! udpsink host=$RECEIVER_IP port=$PORT2_RTCP sync=false async=false \ 46 | " 47 | 48 | export GST_DEBUG="2,screamtx:2" 49 | killall -9 scream_sender 50 | $SCREAM_TARGET_DIR/scream_sender --verbose 51 | -------------------------------------------------------------------------------- /gstscream/scripts/sender_bw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | SCRIPT_PATH=$(realpath $0) 3 | SCRIPT_DIR=$(dirname $SCRIPT_PATH) 4 | source $SCRIPT_DIR/env.sh 5 | 6 | export SENDPIPELINE=" screamtxbw name=encoder0 params=\"-numframes 10000 -initrate 1000 -ssrc 1\" ! queue ! tee name=t t. ! queue ! screamtx name=screamtx0 params=\" -forceidr -ect 1 -initrate 2500 -minrate 500 -maxrate 10000 \" ! udpsink host=$RECEIVER_IP port=$PORT0_RTP sync=false t. ! queue ! fakesink silent=false sync=false rtpbin name=r udpsrc port=$PORT0_RTCP address=$SENDER_IP ! queue ! screamtx0.rtcp_sink screamtx0.rtcp_src ! r.recv_rtcp_sink_0 " 7 | 8 | killall -9 scream_sender 9 | export RUST_BACKTRACE=1 10 | $SCREAM_TARGET_DIR/scream_sender 11 | -------------------------------------------------------------------------------- /gstscream/scripts/sysctl.sh: -------------------------------------------------------------------------------- 1 | set -v 2 | sudo sysctl -w net.core.rmem_max=26214400 3 | sudo sysctl -w net.core.rmem_max=26214400 4 | sudo sysctl -w net.ipv4.udp_rmem_min=409600 5 | 6 | sudo sysctl -w net.core.wmem_max=26214400 7 | sudo sysctl -w net.core.wmem_default=26214400 8 | sudo sysctl -w net.core.rmem_max=26214400 9 | sudo sysctl -w net.core.rmem_default=26214400 10 | 11 | -------------------------------------------------------------------------------- /gstscream/src/lib.rs: -------------------------------------------------------------------------------- 1 | use gst::glib; 2 | 3 | mod screamrx; 4 | #[cfg(not(feature = "screamrx-only"))] 5 | mod screamtx; 6 | #[cfg(all(not(feature = "screamrx-only"), feature = "screamtxbw-enabled"))] 7 | mod screamtxbw; 8 | 9 | // Plugin entry point that should register all elements provided by this plugin, 10 | // and everything else that this plugin might provide (e.g. typefinders or device providers). 11 | fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { 12 | #[cfg(not(feature = "screamrx-only"))] 13 | screamtx::register(plugin)?; 14 | #[cfg(all(not(feature = "screamrx-only"), feature = "screamtxbw-enabled"))] 15 | screamtxbw::register(plugin)?; 16 | screamrx::register(plugin)?; 17 | Ok(()) 18 | } 19 | 20 | // Static plugin metdata that is directly stored in the plugin shared object and read by GStreamer 21 | // upon loading. 22 | // Plugin name, plugin description, plugin entry point function, version number of this plugin, 23 | // license of the plugin, source package name, binary package name, origin where it comes from 24 | // and the date/time of release. 25 | gst::plugin_define!( 26 | scream, 27 | env!("CARGO_PKG_DESCRIPTION"), 28 | plugin_init, 29 | concat!(env!("CARGO_PKG_VERSION"), "-", env!("COMMIT_ID")), 30 | "Proprietary", 31 | env!("CARGO_PKG_NAME"), 32 | env!("CARGO_PKG_NAME"), 33 | env!("CARGO_PKG_REPOSITORY"), 34 | env!("BUILD_REL_DATE") 35 | ); 36 | -------------------------------------------------------------------------------- /gstscream/src/receiver.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::uninlined_format_args)] 2 | extern crate failure; 3 | use std::fmt::Display; 4 | 5 | use clap::Parser; 6 | use failure::Error; 7 | 8 | extern crate gtypes; 9 | 10 | use gst::glib; 11 | use gst::glib::prelude::*; 12 | use gst::prelude::*; 13 | 14 | extern crate chrono; 15 | 16 | #[derive(clap::Parser)] 17 | #[command(version, about, long_about = None)] 18 | struct Arguments { 19 | #[arg(env)] 20 | /// The gstreamer pipeline to use for the receiver application. 21 | recvpipeline: String, 22 | /// Encoder Id , such as 264, 265 23 | #[arg(env, default_value_t = 264)] 24 | enc_id: u32, 25 | } 26 | 27 | fn main() { 28 | let args = Arguments::parse(); 29 | println!("{args}"); 30 | gst::init().expect("Failed to initialize"); 31 | 32 | let main_loop = glib::MainLoop::new(None, false); 33 | 34 | start(&main_loop, args).expect("Failed to start"); 35 | } 36 | 37 | fn start(main_loop: &glib::MainLoop, args: Arguments) -> Result<(), Error> { 38 | let pls: String = args.recvpipeline; 39 | println!("RECVPIPELINE={}", pls); 40 | let pipeline = gst::parse::launch(&pls).unwrap(); 41 | 42 | let pipeline = pipeline.downcast::().unwrap(); 43 | let pipeline_clone = pipeline.clone(); 44 | let bin = pipeline.upcast::(); 45 | let rtpbin = bin.by_name("r").unwrap(); 46 | rtpbin.connect("new-jitterbuffer", false, move |_values| None); 47 | rtpbin.connect("request-pt-map", false, move |values| { 48 | let encoder_name = if args.enc_id == 265 { "H265" } else { "H264" }; 49 | let pt = values[2].get::().expect("Invalid argument"); 50 | println!("got pt: {pt}"); 51 | match pt { 52 | 96 => Some( 53 | gst::Caps::builder("application/x-rtp") 54 | .field("media", "video") 55 | .field("clock-rate", 90000i32) 56 | .field("encoding-name", encoder_name) 57 | .field("rtcp-fb-nack-pli", true) 58 | .build() 59 | .to_value(), 60 | ), 61 | _ => None, 62 | } 63 | }); 64 | 65 | let pipeline = bin.upcast::(); 66 | pipeline 67 | .set_state(gst::State::Playing) 68 | .expect("Failed to set pipeline to `Playing`"); 69 | 70 | let main_loop_clone = main_loop.clone(); 71 | let bus = pipeline_clone.bus().unwrap(); 72 | let _bus_watch = bus 73 | .add_watch(move |_, msg| { 74 | use gst::MessageView; 75 | 76 | let main_loop = &main_loop_clone; 77 | match msg.view() { 78 | MessageView::Eos(..) => { 79 | println!("### got Eos message"); 80 | main_loop.quit(); 81 | } 82 | MessageView::Error(err) => { 83 | println!( 84 | "### error from {:?}: {} ({:?})", 85 | err.src().map(|s| s.path_string()), 86 | err.error(), 87 | err.debug() 88 | ); 89 | main_loop.quit(); 90 | } 91 | _ => (), 92 | }; 93 | glib::ControlFlow::Continue 94 | }) 95 | .expect("failed to add bus watch"); 96 | 97 | main_loop.run(); 98 | pipeline 99 | .set_state(gst::State::Null) 100 | .expect("Failed to set pipeline to `Null`"); 101 | 102 | Ok(()) 103 | } 104 | 105 | impl Display for Arguments { 106 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 107 | write!(f, "Configuration:\n\t- Pipeline {}", self.recvpipeline) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /gstscream/src/screamrx/ecn.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "ecn-enabled")] 2 | mod feature_specific { 3 | use crate::screamrx::imp::CAT; 4 | use gst_sys::GstMeta; 5 | use gtypes::GType; 6 | use libc::c_int; 7 | // Enums 8 | pub type GstNetEcnCp = c_int; 9 | 10 | #[derive(Copy, Clone)] 11 | #[repr(C)] 12 | pub struct GstNetEcnMeta { 13 | pub meta: GstMeta, 14 | pub cp: GstNetEcnCp, 15 | } 16 | 17 | #[link(name = "gstnet-1.0")] 18 | extern "C" { 19 | 20 | //========================================================================= 21 | // GstNetEcnMeta 22 | //========================================================================= 23 | pub fn gst_net_ecn_meta_api_get_type() -> GType; 24 | 25 | } 26 | 27 | pub fn get_ecn(buffer: gst::Buffer, pad: &gst::Pad) -> u8 { 28 | let ecn_ce: u8; 29 | let ecn_meta: *mut GstNetEcnMeta; 30 | unsafe { 31 | ecn_meta = 32 | gst_sys::gst_buffer_get_meta(buffer.as_mut_ptr(), gst_net_ecn_meta_api_get_type()) 33 | as *mut GstNetEcnMeta; 34 | } 35 | if ecn_meta.is_null() { 36 | gst::debug!(CAT, obj = pad, "Buffer did not contain an ECN meta"); 37 | ecn_ce = 0; 38 | } else { 39 | unsafe { 40 | ecn_ce = (*ecn_meta).cp as u8; 41 | } 42 | } 43 | ecn_ce 44 | } 45 | } 46 | #[cfg(not(feature = "ecn-enabled"))] 47 | mod default { 48 | pub fn get_ecn(_buffer: gst::Buffer, _pad: &gst::Pad) -> u8 { 49 | 0 50 | } 51 | } 52 | #[cfg(feature = "ecn-enabled")] 53 | pub use feature_specific::get_ecn; 54 | 55 | #[cfg(not(feature = "ecn-enabled"))] 56 | pub use default::get_ecn; 57 | -------------------------------------------------------------------------------- /gstscream/src/screamrx/mod.rs: -------------------------------------------------------------------------------- 1 | use gst::glib; 2 | use gst::glib::prelude::*; 3 | 4 | mod imp; 5 | 6 | mod ScreamRx; 7 | 8 | mod ecn; 9 | 10 | // The public Rust wrapper type for our element 11 | glib::wrapper! { 12 | pub struct Screamrx(ObjectSubclass) @extends gst::Element, gst::Object; 13 | } 14 | 15 | // GStreamer elements need to be thread-safe. For the private implementation this is automatically 16 | // enforced but for the public wrapper type we need to specify this manually. 17 | unsafe impl Send for Screamrx {} 18 | unsafe impl Sync for Screamrx {} 19 | 20 | // Registers the type for our element, and then registers in GStreamer under 21 | // the name "rsscreamrx" for being able to instantiate it via e.g. 22 | // gst::ElementFactory::make(). 23 | pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { 24 | gst::Element::register( 25 | Some(plugin), 26 | "screamrx", 27 | gst::Rank::NONE, 28 | Screamrx::static_type(), 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /gstscream/src/screamtx/mod.rs: -------------------------------------------------------------------------------- 1 | use gst::glib; 2 | use gst::glib::prelude::*; 3 | 4 | mod imp; 5 | 6 | // The public Rust wrapper type for our element 7 | glib::wrapper! { 8 | pub struct Screamtx(ObjectSubclass) @extends gst::Element, gst::Object; 9 | } 10 | 11 | // GStreamer elements need to be thread-safe. For the private implementation this is automatically 12 | // enforced but for the public wrapper type we need to specify this manually. 13 | unsafe impl Send for Screamtx {} 14 | unsafe impl Sync for Screamtx {} 15 | 16 | // Registers the type for our element, and then registers in GStreamer under 17 | // the name "rsscreamtx" for being able to instantiate it via e.g. 18 | // gst::ElementFactory::make(). 19 | pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { 20 | gst::Element::register( 21 | Some(plugin), 22 | "screamtx", 23 | gst::Rank::NONE, 24 | Screamtx::static_type(), 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /gstscream/src/screamtxbw/mod.rs: -------------------------------------------------------------------------------- 1 | use gst::glib; 2 | use gst::glib::prelude::*; 3 | 4 | mod imp; 5 | 6 | // The public Rust wrapper type for our element 7 | glib::wrapper! { 8 | pub struct Screamtxbw(ObjectSubclass) @extends gst::Element, gst::Object; 9 | } 10 | 11 | // GStreamer elements need to be thread-safe. For the private implementation this is automatically 12 | // enforced but for the public wrapper type we need to specify this manually. 13 | unsafe impl Send for Screamtxbw {} 14 | unsafe impl Sync for Screamtxbw {} 15 | 16 | // Registers the type for our element, and then registers in GStreamer under 17 | // the name "rsscreamtxbw" for being able to instantiate it via e.g. 18 | // gst::ElementFactory::make(). 19 | pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { 20 | gst::Element::register( 21 | Some(plugin), 22 | "screamtxbw", 23 | gst::Rank::NONE, 24 | Screamtxbw::static_type(), 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /gstscream/src/sender.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::uninlined_format_args)] 2 | use clap::Parser; 3 | use failure::Error; 4 | use std::fmt::Display; 5 | use std::process::exit; 6 | 7 | extern crate failure; 8 | #[macro_use] 9 | extern crate lazy_static; 10 | 11 | use gst::glib; 12 | use gst::prelude::*; 13 | 14 | mod sender_util; 15 | 16 | #[derive(clap::Parser)] 17 | #[command(version, about, long_about = None)] 18 | struct Arguments { 19 | #[arg(short, long, default_value_t = false)] 20 | /// Produces verbose logs. 21 | verbose: bool, 22 | 23 | #[arg(short, long)] 24 | /// Rate multiplication factor. 25 | ratemultiply: Option, 26 | 27 | #[arg(env)] 28 | /// The gstreamer pipeline to use for the sender application. 29 | sendpipeline: String, 30 | 31 | #[arg(env, default_value_t = 1000)] 32 | /// The logging interval for sender statistics. 33 | sender_stats_timer: u32, 34 | 35 | #[arg(env, default_value = "sender_scream_stats.csv")] 36 | /// The logging interval for sender statistics. 37 | sender_stats_file_name: std::path::PathBuf, 38 | } 39 | 40 | fn main() { 41 | let args = Arguments::parse(); 42 | println!("{}", args); 43 | 44 | gst::init().expect("Failed to initialize gst_init"); 45 | 46 | let main_loop = glib::MainLoop::new(None, false); 47 | start(&main_loop, args).expect("Failed to start"); 48 | } 49 | 50 | fn start(main_loop: &glib::MainLoop, args: Arguments) -> Result<(), Error> { 51 | let pls = args.sendpipeline; 52 | 53 | println!("Pipeline: {}", pls); 54 | let n_encoder0 = pls.matches("name=encoder0").count(); 55 | let n_encoders = pls.matches("name=encoder").count(); 56 | if n_encoder0 == 0 { 57 | println!("missing name=encoder0"); 58 | exit(0); 59 | } 60 | 61 | let pipeline = gst::parse::launch(&pls).unwrap(); 62 | let pipeline = pipeline.downcast::().unwrap(); 63 | 64 | pipeline 65 | .set_state(gst::State::Playing) 66 | .expect("Failed to set pipeline to `Playing`"); 67 | 68 | let pipeline = pipeline.downcast::().unwrap(); 69 | 70 | let pipeline_clone = pipeline; 71 | /* TBD 72 | * set ecn bits 73 | */ 74 | for n in 0..n_encoders { 75 | let n_string = n.to_string(); 76 | sender_util::stats( 77 | &pipeline_clone, 78 | n, 79 | &Some("screamtx".to_string() + &n_string), 80 | args.sender_stats_timer, 81 | args.sender_stats_file_name.clone(), 82 | ); 83 | sender_util::run_time_bitrate_set( 84 | &pipeline_clone, 85 | args.verbose, 86 | &Some("screamtx".to_string() + &n_string), 87 | &Some("encoder".to_string() + &n_string), 88 | args.ratemultiply, 89 | ); 90 | } 91 | 92 | let main_loop_cloned = main_loop.clone(); 93 | let bus = pipeline_clone.bus().unwrap(); 94 | let _bus_watch = bus 95 | .add_watch(move |_, msg| { 96 | use gst::MessageView; 97 | // println!("sender: {:?}", msg.view()); 98 | match msg.view() { 99 | MessageView::Eos(..) => { 100 | println!("Bus watch Got eos"); 101 | main_loop_cloned.quit(); 102 | } 103 | MessageView::Error(err) => { 104 | println!( 105 | "Error from {:?}: {} ({:?})", 106 | err.src().map(|s| s.path_string()), 107 | err.error(), 108 | err.debug() 109 | ); 110 | } 111 | _ => (), 112 | }; 113 | glib::ControlFlow::Continue 114 | }) 115 | .expect("failed to add bus watch"); 116 | 117 | main_loop.run(); 118 | pipeline_clone 119 | .set_state(gst::State::Null) 120 | .expect("Failed to set pipeline to `Null`"); 121 | println!("Done"); 122 | Ok(()) 123 | } 124 | impl Display for Arguments { 125 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 126 | write!( 127 | f, 128 | "Configuration:\n\t- Verbose: {},\n\t- Ratemultiply: {:?},\n\t- Pipeline: {},\n\t- Logging interval: {},\n\t- sender_stats_file: {}", 129 | self.verbose, 130 | self.ratemultiply, 131 | self.sendpipeline, 132 | self.sender_stats_timer, 133 | self.sender_stats_file_name.display() 134 | ) 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /gstscream/src/sender_util.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::uninlined_format_args)] 2 | use std::convert::TryInto; 3 | use std::fs::File; 4 | use std::io::Write; 5 | use std::sync::{Arc, Mutex}; 6 | use std::time::{Duration, SystemTime, UNIX_EPOCH}; 7 | 8 | use gst::glib; 9 | use gst::prelude::*; 10 | 11 | use glib::timeout_add; 12 | 13 | #[derive(Default)] 14 | struct RateInfo { 15 | rate: u32, 16 | st: Duration, 17 | count: u32, 18 | } 19 | 20 | pub fn stats( 21 | bin: &gst::Pipeline, 22 | n: usize, 23 | screamtx_name_opt: &Option, 24 | sender_stats_timer: u32, 25 | mut sender_stats_file_name: std::path::PathBuf, 26 | ) { 27 | if sender_stats_timer == 0 { 28 | return; 29 | } 30 | 31 | if screamtx_name_opt.is_none() { 32 | println!("no scream name"); 33 | return; 34 | } 35 | 36 | println!("SENDER_STATS_TIMER={}", sender_stats_timer); 37 | 38 | let pipeline_clock = bin.pipeline_clock(); 39 | 40 | let repl_string = "_".to_owned() + &n.to_string() + ".csv"; 41 | let file_name = match sender_stats_file_name.file_name() { 42 | Some(file) => file, 43 | None => { 44 | println!("Invalid SENDER_STATS_FILE_NAME."); 45 | return; 46 | } 47 | }; 48 | let file_name = match file_name.to_str() { 49 | Some(file_name) => file_name, 50 | None => { 51 | println!("SENDER_STATS_FILE_NAME must be a utf8 encoded string"); 52 | return; 53 | } 54 | } 55 | .to_string(); 56 | 57 | sender_stats_file_name.set_file_name(file_name.replace(".csv", &repl_string)); 58 | println!( 59 | "SENDER_STATS_FILE_NAME={}", 60 | sender_stats_file_name.display() 61 | ); 62 | let mut out: File = File::create(&sender_stats_file_name).unwrap(); 63 | 64 | let scream_name = screamtx_name_opt.as_ref().unwrap(); 65 | let screamtx_e = match bin.by_name(scream_name) { 66 | Some(v) => v, 67 | None => { 68 | println!(" no {}", scream_name); 69 | return; 70 | } 71 | }; 72 | 73 | let screamtx_e_clone = screamtx_e.clone(); 74 | let stats_str_header = screamtx_e.property::("stats-header"); 75 | 76 | writeln!(out, "time-ns,{}", stats_str_header).unwrap(); 77 | 78 | let outp_opt: Option>> = Some(Arc::new(Mutex::new(out))); 79 | 80 | timeout_add( 81 | Duration::from_millis(sender_stats_timer as u64), 82 | move || { 83 | let stats_str = screamtx_e_clone.property::("stats"); 84 | 85 | let tm = pipeline_clock.time(); 86 | let ns = tm.unwrap().nseconds(); 87 | let out_p = outp_opt.as_ref().unwrap(); 88 | let mut fd = out_p.lock().unwrap(); 89 | 90 | writeln!(fd, "{},{}", ns, stats_str).unwrap(); 91 | glib::ControlFlow::Continue 92 | }, 93 | ); 94 | } 95 | 96 | lazy_static! { 97 | static ref RATE_INFO_PREV: Mutex = Mutex::new(RateInfo { 98 | ..RateInfo::default() 99 | }); 100 | } 101 | 102 | pub fn run_time_bitrate_set( 103 | bin: &gst::Pipeline, 104 | verbose: bool, 105 | screamtx_name_opt: &Option, 106 | encoder_name_opt: &Option, 107 | ratemultiply_opt: Option, 108 | ) { 109 | if encoder_name_opt.is_none() { 110 | println!("no encoder_name_opt"); 111 | return; 112 | } 113 | let ratemultiply: u32 = ratemultiply_opt.unwrap_or(1).try_into().unwrap(); 114 | println!( 115 | "{:?} {:?} {:?}", 116 | encoder_name_opt, screamtx_name_opt, ratemultiply_opt 117 | ); 118 | let encoder_name = encoder_name_opt.as_ref().unwrap(); 119 | println!("encoder_name {:?}", encoder_name); 120 | let encoder_name_clone = encoder_name.clone(); 121 | let video = bin 122 | .by_name(encoder_name) 123 | .expect("Failed to by_name encoder"); 124 | 125 | let video_cloned = video; 126 | match screamtx_name_opt.as_ref() { 127 | Some(scream_name) => { 128 | match bin.by_name(scream_name) { 129 | Some(scream) => { 130 | let scream_cloned = scream.clone(); 131 | scream.connect("notify::current-max-bitrate", false, move |_values| { 132 | let rate = scream_cloned.property::("current-max-bitrate"); 133 | let rate = rate * ratemultiply; 134 | let prev_br:u32 = video_cloned.property::("bitrate"); 135 | video_cloned 136 | .set_property("bitrate", rate); 137 | let n = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); 138 | 139 | let mut rate_info_prev = RATE_INFO_PREV.lock().unwrap(); 140 | let rate_prev = rate_info_prev.rate; 141 | let st_prev = rate_info_prev.st; 142 | let diff = n.as_secs() - st_prev.as_secs(); 143 | if diff >= 1 { 144 | if rate != rate_prev { 145 | if verbose { 146 | println!("notif: {} {}.{:06} rate {:08} rate_prev {:08} time_prev {}.{:06} diff {} count {} prev_br {}", 147 | encoder_name_clone, n.as_secs(), n.subsec_micros(), rate, rate_prev, st_prev.as_secs(), 148 | st_prev.subsec_micros(), diff, rate_info_prev.count, prev_br); 149 | } 150 | rate_info_prev.rate = rate; 151 | rate_info_prev.st = n; 152 | rate_info_prev.count = 0; 153 | } 154 | } else { 155 | rate_info_prev.count += 1; 156 | // println!("count {}", rate_info_prev.count); 157 | } 158 | None 159 | }); 160 | } 161 | None => println!("no scream signal"), 162 | } 163 | } 164 | None => println!("no scream name"), 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /images/L4S-100Mbps-25ms-0-4-0-TCP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/L4S-100Mbps-25ms-0-4-0-TCP.png -------------------------------------------------------------------------------- /images/L4S-100Mbps-25ms-0-4-TCP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/L4S-100Mbps-25ms-0-4-TCP.png -------------------------------------------------------------------------------- /images/L4S-100Mbps-25ms-r-50-0-4-TCP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/L4S-100Mbps-25ms-r-50-0-4-TCP.png -------------------------------------------------------------------------------- /images/SCReAM-V2-L4S.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/SCReAM-V2-L4S.png -------------------------------------------------------------------------------- /images/SCReAM-V2-RTT-25ms-1360B.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/SCReAM-V2-RTT-25ms-1360B.png -------------------------------------------------------------------------------- /images/SCReAM-V2-noL4S.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/SCReAM-V2-noL4S.png -------------------------------------------------------------------------------- /images/SCReAM_LTE_UL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/SCReAM_LTE_UL.png -------------------------------------------------------------------------------- /images/image_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/image_1.png -------------------------------------------------------------------------------- /images/image_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/image_2.png -------------------------------------------------------------------------------- /images/scream_ecn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/scream_ecn.png -------------------------------------------------------------------------------- /images/scream_ecn_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/scream_ecn_2.png -------------------------------------------------------------------------------- /images/scream_ecn_keyframe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/scream_ecn_keyframe.png -------------------------------------------------------------------------------- /images/scream_l4s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/scream_l4s.png -------------------------------------------------------------------------------- /images/scream_l4s_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/scream_l4s_2.png -------------------------------------------------------------------------------- /images/scream_noecn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/scream_noecn.png -------------------------------------------------------------------------------- /images/scream_noecn_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/scream_noecn_2.png -------------------------------------------------------------------------------- /images/scream_noecn_keyframe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/images/scream_noecn_keyframe.png -------------------------------------------------------------------------------- /multicam/README.md: -------------------------------------------------------------------------------- 1 | # SCReAM multicamera platform 2 | 3 | This README describes the streaming platform for a multicamera solution with SCReAM congestion control. The platform supports up to four cameras and an overview is shown in the figures below (two camera solution).
4 | This streaming solution has been extensively tested for remote control cars but can also be used for e.g drones or remote video production. 5 | 6 | The `capture/encode` and `decode/render` blocks are implemented as GStreamer pipelines, this makes the solution portable to different platforms. The `SCReAM sender` and `SCReAM receiver` blocks builds on Linux platforms and supports ECN and L4S.
7 | 8 | The `SCReAM sender` receives RTP/UDP traffic from the `capture/render` GStreamer pipelines over local ports 30000,30002,30004,30006 and sends codec control commands (target bitrate and force IDR) on local ports 30001,30003,30005,30007. A dedicated `codecctrl` GStreamer plugin serves as an interface between the `SCReAM sender` and the video encoders in the GStreamer piplelines.
9 | 10 | The RTP/UDP streams are multiplexed in the `SCReAM sender` block and transmitted to RECEIVER_IP:UDP_PORT_VIDEO, the RTCP feedback from the receiver is also over the same UDP socket. The `SCReAM receiver` block receives the multiplexed RTP/UDP streams, generates RTCP feedback (RFC8888) to the sender and demultiplexes the streams and forwards them to the `decode/render` GStreamer pipelines. 11 | 12 | 13 | The sender side schematic is according to figure 1 below 14 | 15 | +-----------------+ Lo:30001 +-------------------+ 16 | | +<-----------+ | 17 | | /dev/video0 | | | 18 | | capture/encode +----------->+ | 19 | +-----------------+ Lo:30000 | +---------------------------> 20 | | SCReAM sender | RECEIVER_IP:UDP_PORT_VIDEO 21 | +-----------------+ Lo:30003 | +<--------------------------- 22 | | +<-----------+ | 23 | | /dev/video1 | | | 24 | | capture/encode +----------->+ | 25 | +-----------------+ Lo:30002 +-------------------+ 26 | Figure 1 27 | 28 | The receiver side schematic is according to figure 2 below 29 | 30 | +-------------------+ +-----------------+ 31 | | | Lo:30112 | | 32 | | +----------->+ Front camera | 33 | | | | decode/render | 34 | +----------------->+ | +-----------------+ 35 | $1:UDP_PORT_VIDEO | SCReAM receiver | 36 | <------------------+ | +-----------------+ 37 | | | Lo:30114 | | 38 | | +----------->+ Rear camera | 39 | | | | decode/render | 40 | +-------------------+ +-----------------+ 41 | Figure 2 42 | 43 | ## Start streaming 44 | The sender side is started with he script
45 | `$ ./startsender.sh`
46 | Note that the IP address needs to be changed to point at the receiving side 47 | 48 | The receiver side is started with
49 | `$ ./startreceiver.sh`
50 | This scripts waits for streaming traffic to arrive on the configured UDP port, in addition it also decodes the dst_port in case a NAT has remapped this port. 51 | To ensure proper function it is recommended to start the sender side first, then the receiver side. 52 | 53 | ## Bill of materials 54 | The sender side is built on the NVIDIA Jetson platforms, other platforms and cameras are possible. The BoM for the NVIDIA Jetson is:
55 | * NVIDIA Jetson Nano Rev B01. For improved performance the Xavier NX can be used
56 | * e-CAM50_CUNANO, one or two depending on desired configuration https://www.e-consystems.com/nvidia-cameras/jetson-nano-cameras/5mp-mipi-nano-camera.asp .. or..
57 | * Raspberry PI HQ
58 | * A proper 4G or 5G modem 59 | * A battery 60 | 61 | ## Other platforms 62 | The solution is possible to implement on other Linux based platforms such as Raspberry PI 4. The `SCReAM sender` and `SCReAM receiver` should not need any changes.
63 | The GStreamer pipelines do however need modifications as other hardware video encoders and decoder blocks are used. Furthermore the parameter settings for the `codecctrl` as well as the implementation may need to be modified as different video encoders can use different units ( [bit/s] or [kbit/s] ) and also the parameter name for the target bitrate can vary. 64 | 65 | ## More than two cameras 66 | The scripts in the sender and receiver folders support up to 2 cameras. This can be extended to up to 4 cameras without modifications in the `SCReAM sender` and `SCReAM receiver` code. Platforms such as NVIDIA Jetson AGX Xavier support many cameras, for this purpose the `startsender.sh` and `rendermedia.sh` scripts should be modified to support more cameras. 67 | -------------------------------------------------------------------------------- /multicam/receiver/LICENSE.dat: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Ericsson AB 2 | All rights reserved. 3 | Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met: 4 | 5 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 7 | * Neither the name of Ericsson AB nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 8 | 9 | NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | -------------------------------------------------------------------------------- /multicam/receiver/README.md: -------------------------------------------------------------------------------- 1 | # Receiver side build instructions 2 | 3 | On the receiver side it is assumed that gstreamer is already installed. 4 | 5 | The SCReAM receiver side is built with the instructions
6 | `$cd ./scream`
7 | `$cmake .`
8 | `$make` 9 | 10 | 11 | #Startup 12 | 13 | In the terminal:
14 | `$ ./startvideo.sh`
15 | 16 | To ensure proper function it is recommended to start the sender side first, then the receiver side. Or more correctly, the remote end that is connected to a cellular modem should be started first. This can avoid issues with remapped ports. 17 | 18 | To stop the programs, in the terminal:
19 | `$ ./killitall.sh`
20 | 21 | #Streaming status 22 | Streaming status is printed on stdout and also transmitted on UDP port 30200, this can be used for instance to visualize bitrate, RTT, packet loss etc in a graphical user interface 23 | An example of streaming status is: 24 | *** 396.540, 97, 0.044, 0.010, 609409, 105159, 31465, 1, 0.003, 17433, 18372, 17868, 0, 0, 0.001, 12453, 13480, 13520, 0, 0,
25 | 396.791, 86, 0.042, 0.008, 609409, 92399, 31021, 1, 0.014, 17608, 16876, 17646, 0, 0, 0.000, 12487, 13176, 13298, 0, 0,
26 | 397.042, 88, 0.043, 0.010, 609409, 95279, 31992, 1, 0.012, 17828, 17346, 17979, 0, 0, 0.004, 12573, 13907, 13936, 0, 0,
*** 27 | Where the columns are (listed left to right)
28 | 1. Time [s]
29 | 2. Quality index for first camera (only)
30 | 3. Estimated queue delay [s]
31 | 4. Average RTT [s]
32 | 5. Congestion window [byte]
33 | 6. Bytes in flight [byte]
34 | 7. Total bitrate [kbps]
35 | 8. Fast increase mode indicator [0 or 1]
36 | 9. Camera 1 RTP queue delay [s]
37 | 10. Camera 1 Target bitrate [kbps]
38 | 11. Camera 1 Video coder bitrate [kbps]
39 | 12. Camera 1 Transmitted bitrate [kbps]
40 | 13. Camera 1 Loss bitrate [kbps]
41 | 14. Camera 1 Congestion marked bitrate (ECN, L4S) bitrate [kbps]
42 | 15. Camera 2 RTP queue delay [s]
43 | 16. Camera 2 Target bitrate [kbps]
44 | 17. Camera 2 Video coder bitrate [kbps]
45 | 18. Camera 2 Transmitted bitrate [kbps]
46 | 19. Camera 2 Loss bitrate [kbps]
47 | 20. Camera 2 Congestion marked bitrate (ECN, L4S) bitrate [kbps]
48 | -------------------------------------------------------------------------------- /multicam/receiver/killitall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | killall -9 gst-launch-1.0 4 | killall -9 scream_receiver 5 | 6 | -------------------------------------------------------------------------------- /multicam/receiver/rendermedia-intel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # The receiver side processing is illustrated below 4 | # The SCReAM receiver application receives multiplexed RTP media on port $2 5 | # and transits RTCP feedback over the same port 6 | # The received RTP media is demultiplexed and forwarded on local 7 | # ports 30112, 30114, 31016 and 30118 8 | # The video decoding assumes an NVIDIA Jetson Nano or Xavier NX platform, change to applicable 9 | # HW decoding, depending on platform 10 | # 11 | # +----------------------+ +--------------------+ 12 | # | | Lo:30112 | | 13 | # | +-------------->+ Front camera | 14 | # | | | decode/render | 15 | # +------------------>+ | +--------------------+ 16 | # $1:$2 | SCReAM receiver | 17 | # <-------------------+ | +--------------------+ 18 | # | | Lo:30114 | | 19 | # | +-------------->+ Rear camera | 20 | # | | | decode/render | 21 | # +----------------------+ +--------------------+ 22 | 23 | 24 | # Start SCReAM receiver side 25 | ./scream/bin/scream_receiver $1 $2 $3 | tee ./Data/scream_$4.txt & 26 | 27 | 28 | ## /dev/video0 29 | gst-launch-1.0 udpsrc port=30112 ! application/x-rtp,media=video,clock-rate=90000,encoding-name=H264 ! rtpjitterbuffer latency=50 ! rtph264depay ! h264parse ! vaapih264dec low-latency=true ! videoconvert ! waylandsink sync=true & 30 | 31 | ## /dev/video1 32 | gst-launch-1.0 udpsrc port=30114 ! application/x-rtp,media=video,clock-rate=90000,encoding-name=H264 ! rtpjitterbuffer latency=50 ! rtph264depay ! h264parse ! vaapih264dec low-latency=true ! videoconvert ! ximagesink sync=true & 33 | -------------------------------------------------------------------------------- /multicam/receiver/rendermedia.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # The receiver side processing is illustrated below 4 | # The SCReAM receiver application receives multiplexed RTP media on port $2 5 | # and transits RTCP feedback over the same port 6 | # The received RTP media is demultiplexed and forwarded on local 7 | # ports 30112, 30114, 31016 and 30118 8 | # The video decoding assumes an NVIDIA Jetson Nano or Xavier NX platform, change to applicable 9 | # HW decoding, depending on platform 10 | # 11 | # +----------------------+ +--------------------+ 12 | # | | Lo:30112 | | 13 | # | +-------------->+ Front camera | 14 | # | | | decode/render | 15 | # +------------------>+ | +--------------------+ 16 | # $1:$2 | SCReAM receiver | 17 | # <-------------------+ | +--------------------+ 18 | # | | Lo:30114 | | 19 | # | +-------------->+ Rear camera | 20 | # | | | decode/render | 21 | # +----------------------+ +--------------------+ 22 | 23 | 24 | # Start SCReAM receiver side 25 | ./scream/bin/scream_receiver $1 $2 $3 | tee ./Data/scream_$4.txt & 26 | 27 | 28 | ## /dev/video0 29 | gst-launch-1.0 udpsrc port=30112 ! application/x-rtp,media=video,clock-rate=90000,encoding-name=H264 ! rtpjitterbuffer latency=100 ! rtph264depay ! h264parse ! omxh264dec disable-dpb=true ! nvvidconv ! nveglglessink window-x=640 window-y=360 max-lateness=2000000 sync=true & 30 | 31 | ## /dev/video1 32 | gst-launch-1.0 udpsrc port=30114 ! application/x-rtp,media=video,clock-rate=90000,encoding-name=H264 ! rtpjitterbuffer latency=100 ! rtph264depay ! h264parse ! omxh264dec disable-dpb=true ! nvvidconv ! nveglglessink window-x=960 window-y=0 sync=true & 33 | 34 | -------------------------------------------------------------------------------- /multicam/receiver/scream/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | PROJECT( scream ) 4 | 5 | message("Source Dir:" ${scream_SOURCE_DIR}) 6 | 7 | SET(EXECUTABLE_OUTPUT_PATH ${scream_SOURCE_DIR}/bin) 8 | SET(LIBRARY_OUTPUT_PATH ${scream_SOURCE_DIR}/lib) 9 | SET(RUNTIME_OUTPUT_DIRECTORY ${scream_SOURCE_DIR}/bin) 10 | 11 | SET(scream_BIN ${scream_SOURCE_DIR}/bin) 12 | 13 | message("scream_SOURCE_DIR directories:" ${scream_SOURCE_DIR}) 14 | 15 | IF(UNIX) 16 | add_definitions(-std=c++0x) 17 | ENDIF(UNIX) 18 | 19 | IF(WIN32) 20 | IF(MSVC12) 21 | message("Detected MSVC12 compiler") 22 | set(MSVC_VER VC12) 23 | ELSEIF(MSVC11) 24 | message("Detected MSVC11 compiler") 25 | set(MSVC_VER VC11) 26 | ELSEIF(MSVC10) 27 | message("Detected MSVC10 compiler") 28 | set(MSVC_VER VC10) 29 | ELSEIF(MSVC14) 30 | message("Detected MSVC14 compiler") 31 | set(MSVC_VER VC14) 32 | ELSE(MSVC12) 33 | message("WARNING: Unknown/unsupported MSVC version") 34 | ENDIF(MSVC12) 35 | ENDIF(WIN32) 36 | 37 | if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) 38 | # 64bit 39 | message("Detected 64-bit build - compiling with -fPIC") 40 | SET(CMAKE_CXX_FLAGS "-fPIC -fpermissive -pthread") 41 | else( CMAKE_SIZEOF_VOID_P EQUAL 8 ) 42 | # 32 bit 43 | message("Detected 32-bit build") 44 | SET(CMAKE_CXX_FLAGS "-fPIC -fpermissive -pthread") 45 | endif( CMAKE_SIZEOF_VOID_P EQUAL 8 ) 46 | 47 | SET(screamIncludes 48 | ${scream_SOURCE_DIR} 49 | ${scream_SOURCE_DIR}/code 50 | ) 51 | 52 | message("screamIncludes directories:" ${screamIncludes}) 53 | 54 | # lib directories 55 | IF(WIN32) 56 | SET(screamLink 57 | ${scream_SOURCE_DIR}/../lib 58 | ) 59 | ELSEIF(UNIX) 60 | SET(screamLink 61 | ${scream_SOURCE_DIR}/../lib 62 | /usr/local/lib 63 | /usr/lib 64 | ) 65 | ENDIF(WIN32) 66 | 67 | SET(LibDir 68 | ${scream_SOURCE_DIR}/../lib 69 | ) 70 | 71 | message("LibDir directories:" ${LibDir}) 72 | 73 | # Include directories 74 | INCLUDE_DIRECTORIES( 75 | ${scream_SOURCE_DIR}/../include 76 | ) 77 | 78 | ADD_SUBDIRECTORY( code) 79 | -------------------------------------------------------------------------------- /multicam/receiver/scream/code/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # source files 2 | SET(SRCS 3 | ../../../../code/ScreamRx.cpp 4 | scream_receiver.cpp 5 | ) 6 | 7 | SET(HEADERS 8 | ../../../../code/ScreamRx.h 9 | ) 10 | 11 | SET(SRC_1 12 | ${SRCS} 13 | scream_receiver.cpp 14 | ) 15 | 16 | INCLUDE_DIRECTORIES( 17 | ${screamIncludes} 18 | ../../../../code/ 19 | ) 20 | 21 | LINK_DIRECTORIES( 22 | ${screamLink} 23 | ) 24 | 25 | ADD_EXECUTABLE(scream_receiver ${SRC_1} ${HEADERS}) 26 | 27 | 28 | TARGET_LINK_LIBRARIES ( 29 | scream_receiver 30 | ${screamLibs} 31 | ) 32 | -------------------------------------------------------------------------------- /multicam/receiver/startreceiver-intel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export UDP_PORT_VIDEO=51000 4 | 5 | # UDP source ports mahy on occations become remapped, therefore this extra code is needed 6 | # to make sure that RTCP feedback to sender side finds its way through 7 | # This is normally not something that is needed if VPN is used 8 | SND_IP_PORT=$(sudo tcpdump -c 1 -n udp port $UDP_PORT_VIDEO 2> /dev/null | sed -e 's/.*IP\(.*\)>.*/\1/') 9 | UDP_SRC_PORT=$(echo $SND_IP_PORT | sed -e 's/.*\.//') 10 | SENDER_IP=$(echo $SND_IP_PORT | sed 's![^.]*$!!' | sed 's/.$//') 11 | 12 | DATE=`date +%y-%m-%d_%H%M%S` 13 | echo "Video streaming IP address and UDP source port " $SENDER_IP " " $UDP_SRC_PORT 14 | 15 | export SND_IP 16 | export UDP_SRC_PORT 17 | ./rendermedia-intel.sh $SENDER_IP $UDP_PORT_VIDEO $UDP_SRC_PORT $DATE 18 | -------------------------------------------------------------------------------- /multicam/receiver/startreceiver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export UDP_PORT_VIDEO=51000 4 | 5 | # UDP source ports mahy on occations become remapped, therefore this extra code is needed 6 | # to make sure that RTCP feedback to sender side finds its way through 7 | # This is normally not something that is needed if VPN is used 8 | SND_IP_PORT=$(sudo tcpdump -c 1 -n udp port $UDP_PORT_VIDEO 2> /dev/null | sed -e 's/.*IP\(.*\)>.*/\1/') 9 | UDP_SRC_PORT=$(echo $SND_IP_PORT | sed -e 's/.*\.//') 10 | SENDER_IP=$(echo $SND_IP_PORT | sed 's![^.]*$!!' | sed 's/.$//') 11 | 12 | DATE=`date +%y-%m-%d_%H%M%S` 13 | echo "Video streaming IP address and UDP source port " $SND_IP " " $UDP_SRC_PORT 14 | 15 | export SND_IP 16 | export UDP_SRC_PORT 17 | ./rendermedia.sh $SENDER_IP $UDP_PORT_VIDEO $UDP_SRC_PORT $DATE 18 | -------------------------------------------------------------------------------- /multicam/sender/LICENSE.dat: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Ericsson AB 2 | All rights reserved. 3 | Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met: 4 | 5 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 7 | * Neither the name of Ericsson AB nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 8 | 9 | NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /multicam/sender/README.md: -------------------------------------------------------------------------------- 1 | # Sender side build instructions 2 | 3 | The NVIDIA is built with the Jetpack and install scripts provided by e-consystems.com upon purchase of the cameras. Make sure that the correct Jetpack version is used as e-consystems may lag behind the Jetpack updates slighly. 4 | 5 | The sender side platform contains interfacing with the gstreamer framework 6 | and the SCReAM congestion control. The SCReAM congestion control is currently 7 | run in a stand alone application outside the gstreamer pipeline as it is necessary 8 | to congestion control 2 streams 9 | 10 | ## codecctrl 11 | The gstreamer codec control is a plugin that serves as an interface between the SCReAM multi 12 | stream congestion control and the gstreamer video encoding entities 13 | 14 | **1. Install applicable gstreamer thingys** 15 | You need these 16 | https://developer.ridgerun.com/wiki/index.php?title=Setting_a_GStreamer_Alternative_Environment 17 | `sudo apt-get install pkg-config bison flex git libglib2.0-dev liborc-0.4-dev libtool autopoint autoconf gettext yasm` 18 | 19 | From https://gstreamer.freedesktop.org/documentation/installing/on-linux.html 20 | `$ apt-get install libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x` 21 | 22 | In addition you need 23 | 24 | `$ sudo apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev` 25 | 26 | **2. Set path** 27 | 28 | `export GST_PLUGIN_PATH=/usr/local/lib/gstreamer-1.0/` 29 | 30 | **3. Make codecctrl plugin** 31 | 32 | `cd ./gst-codec-ctrl/gst-plugin` 33 | 34 | `chmod +x autogen.sh` 35 | 36 | `chmod +x config.status` 37 | 38 | `./autogen.sh` 39 | 40 | `sudo make install` 41 | 42 | **Issue.** File glibconfig.h is missing when gscream plugin is built. 43 | 44 | **Solution** copy file glibconfig.h from 45 | /usr/lib/aarch64-linux-gnu/glib-2.0/include/ (or where it may be) 46 | to 47 | /usr/include/glib-2.0 48 | 49 | **4. Install v4l2-ctl 50 | `sudo apt-get install -y v4l-utils` 51 | 52 | **5. Build SCReAM sender side 53 | The SCReAM sender side is built with the instructions 54 | `$ cd ./scream` 55 | `$ cmake .` 56 | `$ make` 57 | 58 | To enable SCReAM V2, change SET(CMAKE_CXX_FLAGS "-fPIC -fpermissive -pthread") to SET(CMAKE_CXX_FLAGS "-fPIC -fpermissive -pthread -DV2") in CMakeLists.txt 59 | Note also then that SCREAM_VERSION="V2" is needed in startsender.sh 60 | 61 | 62 | **5. Start streaming 63 | `$ ./startsender.sh` 64 | 65 | To ensure proper function it is recommended to start the sender side first, then the receiver side. Or more correctly, the remote end that is connected to a cellular modem should be started first. This can avoid issues with remapped ports. 66 | -------------------------------------------------------------------------------- /multicam/sender/default.scream: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/multicam/sender/default.scream -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/AUTHORS: -------------------------------------------------------------------------------- 1 | Thomas Vander Stichele 2 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/COPYING: -------------------------------------------------------------------------------- 1 | Put your license in here! 2 | 3 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/ChangeLog: -------------------------------------------------------------------------------- 1 | 2008-11-04 Stefan Kost 2 | 3 | * src/Makefile.am: 4 | Don't install static libs for plugins. Fixes #550851 for the template. 5 | 6 | 2008-10-30 Stefan Kost 7 | 8 | * tools/make_element: 9 | Don't replace GstPlugin. 10 | 11 | 2008-08-11 Stefan Kost 12 | 13 | * README: 14 | * src/gstaudiofilter.c: 15 | * src/gstplugin.c: 16 | * src/gsttransform.c: 17 | * tools/make_element: 18 | Integrate new template and improve search'n'replace ops. Update 19 | templates to use current API. 20 | 21 | 2008-07-26 Stefan Kost 22 | 23 | * tools/make_element: 24 | Fix username detection. tries getent first and falls back to grep 25 | passwd. Spotted by Karoly Segesdi. 26 | 27 | 2008-06-09 Jan Schmidt 28 | 29 | * src/gstplugin.c: 30 | Fix some memory leaks, and make the setcaps function actually 31 | sets the caps on the other pad. 32 | 33 | 2008-05-08 Stefan Kost 34 | 35 | * README: 36 | Add simple usage explanation and make it look like the other READMEs. 37 | 38 | * src/gstplugin.c: 39 | * src/gstplugin.h: 40 | * src/gsttransform.c: 41 | * src/gsttransform.h: 42 | * tools/make_element: 43 | Add year, username and email fields. Update the templates here and 44 | there a bit. Add more comments. 45 | 46 | 2007-08-01 Tim-Philipp Müller 47 | 48 | * src/gsttransform.c: 49 | Include right header to avoid structure size mismatches etc. 50 | 51 | 2007-07-25 Tim-Philipp Müller 52 | 53 | Patch by: Steve Fink 54 | 55 | * src/gstplugin.c: 56 | Use GST_DEBUG_FUNCPTR() macros where it makes sense. 57 | 58 | 2007-07-19 Stefan Kost 59 | 60 | * configure.ac: 61 | Fix CVS-build detection. 62 | 63 | 2007-01-23 Tim-Philipp Müller 64 | 65 | * src/Makefile.am: 66 | Make clearer which Makefile variables need renaming if the plugin 67 | name is changes (#399746) (pretty it is not, but it's the content 68 | that counts, right?) 69 | 70 | 2007-01-22 Tim-Philipp Müller 71 | 72 | Patch by: Philip Jägenstedt 73 | 74 | * tools/make_element: 75 | Translate FOO_IS_MY_PLUGIN macro as well according to the template 76 | (#399323). 77 | 78 | 2006-07-04 Tim-Philipp Müller 79 | 80 | * autogen.sh: 81 | Run autoheader to create config.h.in and fix the build.` 82 | 83 | 2006-07-03 Tim-Philipp Müller 84 | 85 | * Makefile.am: 86 | * autogen.sh: 87 | * gst-autogen.sh: 88 | Throw an error if autotools versions are too old. We require 89 | automake 1.7 or newer (#346054). Add gst-autogen.sh to check 90 | for this. 91 | 92 | * COPYING: 93 | Add placeholder COPYING file so it doesn't get overwritten 94 | by a GPL one by automake. 95 | 96 | 2006-06-22 Tim-Philipp Müller 97 | 98 | Patch by: Philip Jägenstedt 99 | 100 | * src/gstplugin.c: (gst_plugin_template_base_init), 101 | (gst_plugin_template_class_init), (gst_plugin_template_init), 102 | (plugin_init): 103 | Use GST_BOILERPLATE, add debug category (#345601). 104 | 105 | 2006-04-20 Stefan Kost 106 | 107 | Patch by: Johan Rydberg 108 | 109 | * src/gstplugin.c: (gst_plugin_template_get_type), 110 | (gst_plugin_template_base_init), (gst_plugin_template_class_init), 111 | (gst_plugin_template_set_property), 112 | (gst_plugin_template_get_property): 113 | * src/gstplugin.h: 114 | * src/gsttransform.c: (gst_plugin_template_base_init), 115 | (gst_plugin_template_set_property), 116 | (gst_plugin_template_get_property): 117 | * tools/make_element: 118 | remove double gst_get_, fix '_' in names 119 | 120 | 121 | 2006-02-26 Tim-Philipp Müller 122 | 123 | * src/gstplugin.c: (gst_plugin_template_init), 124 | (gst_plugin_template_chain): 125 | Fix function declaration of _init() function. 126 | Remove unnecessary assertion clutter in chain function 127 | (that also failed to return a flow value, causing 128 | compiler warnings). 129 | 130 | 2006-02-07 Stefan Kost 131 | 132 | * src/gstplugin.c: (gst_plugin_template_set_caps), 133 | (gst_plugin_template_chain): 134 | * src/gsttransform.c: (gst_plugin_template_transform_ip): 135 | more code cleanups, more comments 136 | 137 | 2006-02-07 Stefan Kost 138 | 139 | * configure.ac: 140 | allow installing to $HOME 141 | * src/gstplugin.c: (gst_plugin_template_base_init), 142 | (gst_plugin_template_init): 143 | * src/gstplugin.h: 144 | * src/gsttransform.c: (gst_plugin_template_base_init), 145 | (gst_plugin_template_class_init), (gst_plugin_template_init), 146 | (gst_plugin_template_transform_ip), 147 | (gst_plugin_template_set_property), 148 | (gst_plugin_template_get_property), (plugin_init): 149 | * src/gsttransform.h: 150 | add another template 151 | * tools/make_element: 152 | fix generator, when template (arg2) is given 153 | 154 | 2006-01-23 Tim-Philipp Müller 155 | 156 | * src/gstplugin.h: 157 | FOO_BAR_CLASS(klass) should cast to FooBarClass*, 158 | not FooBar*. 159 | 160 | 2006-01-13 Thomas Vander Stichele 161 | 162 | * autogen.sh: 163 | * configure.ac: 164 | * src/Makefile.am: 165 | * src/gstplugin.c: 166 | bring into the 0.10 world 167 | Fix #315582 168 | 169 | 2005-12-16 Jan Schmidt 170 | 171 | * src/gstplugin.c: (gst_plugin_template_class_init): 172 | Need to have the set_property and get_property methods 173 | before installing properties 174 | 175 | 2005-12-14 Tim-Philipp Müller 176 | 177 | * src/gstplugin.h: 178 | Fix GST_IS_FOO_BAR_CLASS macro. 179 | 180 | 2005-06-30 Ronald S. Bultje 181 | 182 | * configure.ac: 183 | * src/gstplugin.c: (gst_plugin_template_set_caps), 184 | (gst_plugin_template_init), (gst_plugin_template_chain): 185 | Fix for GStreamer 0.9. 186 | 187 | 2004-04-22 Thomas Vander Stichele 188 | 189 | * Makefile.am: 190 | * autogen.sh: 191 | * configure.ac: 192 | * src/Makefile.am: 193 | use proper LDFLAGS for plugins 194 | run in maintainer mode by default 195 | 196 | 2004-04-22 Thomas Vander Stichele 197 | 198 | * configure.ac: ... and fix comments too 199 | 200 | 2004-04-03 Benjamin Otte 201 | 202 | * configure.ac: 203 | update for GStreamer 0.8 204 | 205 | 2004-01-25 Ronald Bultje 206 | 207 | * src/gstplugin.c: (gst_plugin_template_link), 208 | (gst_plugin_template_base_init), (gst_plugin_template_init): 209 | Fix for GStreamer 0.7.x. 210 | 211 | 2003-02-06 Thomas Vander Stichele 212 | 213 | * updated for GStreamer 0.6.0 214 | 215 | 2002-07-17 Thomas Vander Stichele 216 | 217 | * initial creation on a flight to New York 218 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src 2 | 3 | EXTRA_DIST = autogen.sh 4 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/NEWS: -------------------------------------------------------------------------------- 1 | Nothing much yet. 2 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/README: -------------------------------------------------------------------------------- 1 | WHAT IT IS 2 | ---------- 3 | 4 | gst-plugin is a template for writing your own GStreamer plug-in. 5 | 6 | The code is deliberately kept simple so that you quickly understand the basics 7 | of how to set up autotools and your source tree. 8 | 9 | This template demonstrates : 10 | - what to do in autogen.sh 11 | - how to setup configure.ac (your package name and version, GStreamer flags) 12 | - how to setup your source dir 13 | - what to put in Makefile.am 14 | 15 | More features and templates might get added later on. 16 | 17 | HOW TO USE IT 18 | ------------- 19 | 20 | To use it, either make a copy for yourself and rename the parts or use the 21 | make_element script in tools. To create sources for "myfilter" based on the 22 | "gsttransform" template run: 23 | 24 | cd src; 25 | ../tools/make_element myfilter gsttransform 26 | 27 | This will create gstmyfilter.c and gstmyfilter.h. Open them in an editor and 28 | start editing. There are several occurances of the string "template", update 29 | those with real values. The plugin will be called 'myfilter' and it will have 30 | one element called 'myfilter' too. Also look for "FIXME:" markers that point you 31 | to places where you need to edit the code. 32 | 33 | You still need to adjust the Makefile.am. 34 | 35 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # you can either set the environment variables AUTOCONF, AUTOHEADER, AUTOMAKE, 3 | # ACLOCAL, AUTOPOINT and/or LIBTOOLIZE to the right versions, or leave them 4 | # unset and get the defaults 5 | 6 | autoreconf --verbose --force --install --make || { 7 | echo 'autogen.sh failed'; 8 | exit 1; 9 | } 10 | 11 | ./configure || { 12 | echo 'configure failed'; 13 | exit 1; 14 | } 15 | 16 | echo 17 | echo "Now type 'make' to compile this module." 18 | echo 19 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/config.h: -------------------------------------------------------------------------------- 1 | /* config.h. Generated from config.h.in by configure. */ 2 | /* config.h.in. Generated from configure.ac by autoheader. */ 3 | 4 | /* Define to 1 if you have the header file. */ 5 | #define HAVE_DLFCN_H 1 6 | 7 | /* Define to 1 if you have the header file. */ 8 | #define HAVE_INTTYPES_H 1 9 | 10 | /* Define to 1 if you have the header file. */ 11 | #define HAVE_MEMORY_H 1 12 | 13 | /* Define to 1 if you have the header file. */ 14 | #define HAVE_STDINT_H 1 15 | 16 | /* Define to 1 if you have the header file. */ 17 | #define HAVE_STDLIB_H 1 18 | 19 | /* Define to 1 if you have the header file. */ 20 | #define HAVE_STRINGS_H 1 21 | 22 | /* Define to 1 if you have the header file. */ 23 | #define HAVE_STRING_H 1 24 | 25 | /* Define to 1 if you have the header file. */ 26 | #define HAVE_SYS_STAT_H 1 27 | 28 | /* Define to 1 if you have the header file. */ 29 | #define HAVE_SYS_TYPES_H 1 30 | 31 | /* Define to 1 if you have the header file. */ 32 | #define HAVE_UNISTD_H 1 33 | 34 | /* Define to the sub-directory where libtool stores uninstalled libraries. */ 35 | #define LT_OBJDIR ".libs/" 36 | 37 | /* Name of package */ 38 | #define PACKAGE "my-plugin-package" 39 | 40 | /* Define to the address where bug reports for this package should be sent. */ 41 | #define PACKAGE_BUGREPORT "" 42 | 43 | /* Define to the full name of this package. */ 44 | #define PACKAGE_NAME "my-plugin-package" 45 | 46 | /* Define to the full name and version of this package. */ 47 | #define PACKAGE_STRING "my-plugin-package 1.0.0" 48 | 49 | /* Define to the one symbol short name of this package. */ 50 | #define PACKAGE_TARNAME "my-plugin-package" 51 | 52 | /* Define to the home page for this package. */ 53 | #define PACKAGE_URL "" 54 | 55 | /* Define to the version of this package. */ 56 | #define PACKAGE_VERSION "1.0.0" 57 | 58 | /* Define to 1 if you have the ANSI C header files. */ 59 | #define STDC_HEADERS 1 60 | 61 | /* Version number of package */ 62 | #define VERSION "1.0.0" 63 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if you have the header file. */ 4 | #undef HAVE_DLFCN_H 5 | 6 | /* Define to 1 if you have the header file. */ 7 | #undef HAVE_INTTYPES_H 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #undef HAVE_MEMORY_H 11 | 12 | /* Define to 1 if you have the header file. */ 13 | #undef HAVE_STDINT_H 14 | 15 | /* Define to 1 if you have the header file. */ 16 | #undef HAVE_STDLIB_H 17 | 18 | /* Define to 1 if you have the header file. */ 19 | #undef HAVE_STRINGS_H 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #undef HAVE_STRING_H 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_SYS_STAT_H 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #undef HAVE_SYS_TYPES_H 29 | 30 | /* Define to 1 if you have the header file. */ 31 | #undef HAVE_UNISTD_H 32 | 33 | /* Define to the sub-directory where libtool stores uninstalled libraries. */ 34 | #undef LT_OBJDIR 35 | 36 | /* Name of package */ 37 | #undef PACKAGE 38 | 39 | /* Define to the address where bug reports for this package should be sent. */ 40 | #undef PACKAGE_BUGREPORT 41 | 42 | /* Define to the full name of this package. */ 43 | #undef PACKAGE_NAME 44 | 45 | /* Define to the full name and version of this package. */ 46 | #undef PACKAGE_STRING 47 | 48 | /* Define to the one symbol short name of this package. */ 49 | #undef PACKAGE_TARNAME 50 | 51 | /* Define to the home page for this package. */ 52 | #undef PACKAGE_URL 53 | 54 | /* Define to the version of this package. */ 55 | #undef PACKAGE_VERSION 56 | 57 | /* Define to 1 if you have the ANSI C header files. */ 58 | #undef STDC_HEADERS 59 | 60 | /* Version number of package */ 61 | #undef VERSION 62 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/config.h.in~: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if you have the header file. */ 4 | #undef HAVE_DLFCN_H 5 | 6 | /* Define to 1 if you have the header file. */ 7 | #undef HAVE_INTTYPES_H 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #undef HAVE_MEMORY_H 11 | 12 | /* Define to 1 if you have the header file. */ 13 | #undef HAVE_STDINT_H 14 | 15 | /* Define to 1 if you have the header file. */ 16 | #undef HAVE_STDLIB_H 17 | 18 | /* Define to 1 if you have the header file. */ 19 | #undef HAVE_STRINGS_H 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #undef HAVE_STRING_H 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_SYS_STAT_H 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #undef HAVE_SYS_TYPES_H 29 | 30 | /* Define to 1 if you have the header file. */ 31 | #undef HAVE_UNISTD_H 32 | 33 | /* Define to the sub-directory where libtool stores uninstalled libraries. */ 34 | #undef LT_OBJDIR 35 | 36 | /* Name of package */ 37 | #undef PACKAGE 38 | 39 | /* Define to the address where bug reports for this package should be sent. */ 40 | #undef PACKAGE_BUGREPORT 41 | 42 | /* Define to the full name of this package. */ 43 | #undef PACKAGE_NAME 44 | 45 | /* Define to the full name and version of this package. */ 46 | #undef PACKAGE_STRING 47 | 48 | /* Define to the one symbol short name of this package. */ 49 | #undef PACKAGE_TARNAME 50 | 51 | /* Define to the home page for this package. */ 52 | #undef PACKAGE_URL 53 | 54 | /* Define to the version of this package. */ 55 | #undef PACKAGE_VERSION 56 | 57 | /* Define to 1 if you have the ANSI C header files. */ 58 | #undef STDC_HEADERS 59 | 60 | /* Version number of package */ 61 | #undef VERSION 62 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/configure.ac: -------------------------------------------------------------------------------- 1 | dnl required version of autoconf 2 | AC_PREREQ([2.53]) 3 | 4 | dnl TODO: fill in your package name and package version here 5 | AC_INIT([my-plugin-package],[1.0.0]) 6 | 7 | dnl required versions of gstreamer and plugins-base 8 | GST_REQUIRED=1.0.0 9 | GSTPB_REQUIRED=1.0.0 10 | 11 | AC_CONFIG_SRCDIR([src/gstplugin.cpp]) 12 | AC_CONFIG_HEADERS([config.h]) 13 | 14 | dnl required version of automake 15 | AM_INIT_AUTOMAKE([1.10]) 16 | 17 | dnl enable mainainer mode by default 18 | AM_MAINTAINER_MODE([enable]) 19 | 20 | dnl check for tools (compiler etc.) 21 | AC_PROG_CC 22 | 23 | AC_PROG_CXX 24 | dnl required version of libtool 25 | LT_PREREQ([2.2.6]) 26 | LT_INIT 27 | 28 | dnl give error and exit if we don't have pkgconfig 29 | AC_CHECK_PROG(HAVE_PKGCONFIG, pkg-config, [ ], [ 30 | AC_MSG_ERROR([You need to have pkg-config installed!]) 31 | ]) 32 | 33 | dnl Check for the required version of GStreamer core (and gst-plugins-base) 34 | dnl This will export GST_CFLAGS and GST_LIBS variables for use in Makefile.am 35 | dnl 36 | dnl If you need libraries from gst-plugins-base here, also add: 37 | dnl for libgstaudio-1.0: gstreamer-audio-1.0 >= $GST_REQUIRED 38 | dnl for libgstvideo-1.0: gstreamer-video-1.0 >= $GST_REQUIRED 39 | dnl for libgsttag-1.0: gstreamer-tag-1.0 >= $GST_REQUIRED 40 | dnl for libgstpbutils-1.0: gstreamer-pbutils-1.0 >= $GST_REQUIRED 41 | dnl for libgstfft-1.0: gstreamer-fft-1.0 >= $GST_REQUIRED 42 | dnl for libgstinterfaces-1.0: gstreamer-interfaces-1.0 >= $GST_REQUIRED 43 | dnl for libgstrtp-1.0: gstreamer-rtp-1.0 >= $GST_REQUIRED 44 | dnl for libgstrtsp-1.0: gstreamer-rtsp-1.0 >= $GST_REQUIRED 45 | dnl etc. 46 | PKG_CHECK_MODULES(GST, [ 47 | gstreamer-1.0 >= $GST_REQUIRED 48 | gstreamer-base-1.0 >= $GST_REQUIRED 49 | gstreamer-controller-1.0 >= $GST_REQUIRED 50 | gstreamer-audio-1.0 >= $GST_REQUIRED 51 | gstreamer-rtp-1.0 >= $GST_REQUIRED 52 | ], [ 53 | AC_SUBST(GST_CFLAGS) 54 | AC_SUBST(GST_LIBS) 55 | ], [ 56 | AC_MSG_ERROR([ 57 | You need to install or upgrade the GStreamer development 58 | packages on your system. On debian-based systems these are 59 | libgstreamer1.0-dev and libgstreamer-plugins-base1.0-dev. 60 | on RPM-based systems gstreamer1.0-devel, libgstreamer1.0-devel 61 | or similar. The minimum version required is $GST_REQUIRED. 62 | ]) 63 | ]) 64 | 65 | dnl check if compiler understands -Wall (if yes, add -Wall to GST_CFLAGS) 66 | AC_MSG_CHECKING([to see if compiler understands -Wall]) 67 | save_CFLAGS="$CFLAGS" 68 | CFLAGS="$CFLAGS -Wall" 69 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ ], [ ])], [ 70 | GST_CFLAGS="$GST_CFLAGS -Wall" 71 | AC_MSG_RESULT([yes]) 72 | ], [ 73 | AC_MSG_RESULT([no]) 74 | ]) 75 | 76 | dnl set the plugindir where plugins should be installed (for src/Makefile.am) 77 | if test "x${prefix}" = "x$HOME"; then 78 | plugindir="$HOME/.gstreamer-1.0/plugins" 79 | else 80 | plugindir="\$(libdir)/gstreamer-1.0" 81 | fi 82 | AC_SUBST(plugindir) 83 | 84 | dnl set proper LDFLAGS for plugins 85 | GST_PLUGIN_LDFLAGS='-module -avoid-version -export-symbols-regex [_]*\(gst_\|Gst\|GST_\).*' 86 | AC_SUBST(GST_PLUGIN_LDFLAGS) 87 | 88 | AC_CONFIG_FILES([Makefile src/Makefile]) 89 | AC_OUTPUT 90 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common wrapper for a few potentially missing GNU programs. 3 | 4 | scriptversion=2013-10-28.13; # UTC 5 | 6 | # Copyright (C) 1996-2014 Free Software Foundation, Inc. 7 | # Originally written by Fran,cois Pinard , 1996. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | if test $# -eq 0; then 28 | echo 1>&2 "Try '$0 --help' for more information" 29 | exit 1 30 | fi 31 | 32 | case $1 in 33 | 34 | --is-lightweight) 35 | # Used by our autoconf macros to check whether the available missing 36 | # script is modern enough. 37 | exit 0 38 | ;; 39 | 40 | --run) 41 | # Back-compat with the calling convention used by older automake. 42 | shift 43 | ;; 44 | 45 | -h|--h|--he|--hel|--help) 46 | echo "\ 47 | $0 [OPTION]... PROGRAM [ARGUMENT]... 48 | 49 | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due 50 | to PROGRAM being missing or too old. 51 | 52 | Options: 53 | -h, --help display this help and exit 54 | -v, --version output version information and exit 55 | 56 | Supported PROGRAM values: 57 | aclocal autoconf autoheader autom4te automake makeinfo 58 | bison yacc flex lex help2man 59 | 60 | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 61 | 'g' are ignored when checking the name. 62 | 63 | Send bug reports to ." 64 | exit $? 65 | ;; 66 | 67 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 68 | echo "missing $scriptversion (GNU Automake)" 69 | exit $? 70 | ;; 71 | 72 | -*) 73 | echo 1>&2 "$0: unknown '$1' option" 74 | echo 1>&2 "Try '$0 --help' for more information" 75 | exit 1 76 | ;; 77 | 78 | esac 79 | 80 | # Run the given program, remember its exit status. 81 | "$@"; st=$? 82 | 83 | # If it succeeded, we are done. 84 | test $st -eq 0 && exit 0 85 | 86 | # Also exit now if we it failed (or wasn't found), and '--version' was 87 | # passed; such an option is passed most likely to detect whether the 88 | # program is present and works. 89 | case $2 in --version|--help) exit $st;; esac 90 | 91 | # Exit code 63 means version mismatch. This often happens when the user 92 | # tries to use an ancient version of a tool on a file that requires a 93 | # minimum version. 94 | if test $st -eq 63; then 95 | msg="probably too old" 96 | elif test $st -eq 127; then 97 | # Program was missing. 98 | msg="missing on your system" 99 | else 100 | # Program was found and executed, but failed. Give up. 101 | exit $st 102 | fi 103 | 104 | perl_URL=http://www.perl.org/ 105 | flex_URL=http://flex.sourceforge.net/ 106 | gnu_software_URL=http://www.gnu.org/software 107 | 108 | program_details () 109 | { 110 | case $1 in 111 | aclocal|automake) 112 | echo "The '$1' program is part of the GNU Automake package:" 113 | echo "<$gnu_software_URL/automake>" 114 | echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" 115 | echo "<$gnu_software_URL/autoconf>" 116 | echo "<$gnu_software_URL/m4/>" 117 | echo "<$perl_URL>" 118 | ;; 119 | autoconf|autom4te|autoheader) 120 | echo "The '$1' program is part of the GNU Autoconf package:" 121 | echo "<$gnu_software_URL/autoconf/>" 122 | echo "It also requires GNU m4 and Perl in order to run:" 123 | echo "<$gnu_software_URL/m4/>" 124 | echo "<$perl_URL>" 125 | ;; 126 | esac 127 | } 128 | 129 | give_advice () 130 | { 131 | # Normalize program name to check for. 132 | normalized_program=`echo "$1" | sed ' 133 | s/^gnu-//; t 134 | s/^gnu//; t 135 | s/^g//; t'` 136 | 137 | printf '%s\n' "'$1' is $msg." 138 | 139 | configure_deps="'configure.ac' or m4 files included by 'configure.ac'" 140 | case $normalized_program in 141 | autoconf*) 142 | echo "You should only need it if you modified 'configure.ac'," 143 | echo "or m4 files included by it." 144 | program_details 'autoconf' 145 | ;; 146 | autoheader*) 147 | echo "You should only need it if you modified 'acconfig.h' or" 148 | echo "$configure_deps." 149 | program_details 'autoheader' 150 | ;; 151 | automake*) 152 | echo "You should only need it if you modified 'Makefile.am' or" 153 | echo "$configure_deps." 154 | program_details 'automake' 155 | ;; 156 | aclocal*) 157 | echo "You should only need it if you modified 'acinclude.m4' or" 158 | echo "$configure_deps." 159 | program_details 'aclocal' 160 | ;; 161 | autom4te*) 162 | echo "You might have modified some maintainer files that require" 163 | echo "the 'autom4te' program to be rebuilt." 164 | program_details 'autom4te' 165 | ;; 166 | bison*|yacc*) 167 | echo "You should only need it if you modified a '.y' file." 168 | echo "You may want to install the GNU Bison package:" 169 | echo "<$gnu_software_URL/bison/>" 170 | ;; 171 | lex*|flex*) 172 | echo "You should only need it if you modified a '.l' file." 173 | echo "You may want to install the Fast Lexical Analyzer package:" 174 | echo "<$flex_URL>" 175 | ;; 176 | help2man*) 177 | echo "You should only need it if you modified a dependency" \ 178 | "of a man page." 179 | echo "You may want to install the GNU Help2man package:" 180 | echo "<$gnu_software_URL/help2man/>" 181 | ;; 182 | makeinfo*) 183 | echo "You should only need it if you modified a '.texi' file, or" 184 | echo "any other file indirectly affecting the aspect of the manual." 185 | echo "You might want to install the Texinfo package:" 186 | echo "<$gnu_software_URL/texinfo/>" 187 | echo "The spurious makeinfo call might also be the consequence of" 188 | echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" 189 | echo "want to install GNU make:" 190 | echo "<$gnu_software_URL/make/>" 191 | ;; 192 | *) 193 | echo "You might have modified some files without having the proper" 194 | echo "tools for further handling them. Check the 'README' file, it" 195 | echo "often tells you about the needed prerequisites for installing" 196 | echo "this package. You may also peek at any GNU archive site, in" 197 | echo "case some other package contains this missing '$1' program." 198 | ;; 199 | esac 200 | } 201 | 202 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ 203 | -e '2,$s/^/ /' >&2 204 | 205 | # Propagate the correct exit status (expected to be 127 for a program 206 | # not found, 63 for a program that failed due to version mismatch). 207 | exit $st 208 | 209 | # Local variables: 210 | # eval: (add-hook 'write-file-hooks 'time-stamp) 211 | # time-stamp-start: "scriptversion=" 212 | # time-stamp-format: "%:y-%02m-%02d.%02H" 213 | # time-stamp-time-zone: "UTC" 214 | # time-stamp-end: "; # UTC" 215 | # End: 216 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/src/.libs/libgstcodecctrl.exp: -------------------------------------------------------------------------------- 1 | gst_g_codecctrl_get_type 2 | gst_plugin_codecctrl_get_desc 3 | gst_plugin_codecctrl_register 4 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/src/.libs/libgstcodecctrl.lai: -------------------------------------------------------------------------------- 1 | # libgstcodecctrl.la - a libtool library file 2 | # Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-2 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # The name that we can dlopen(3). 8 | dlname='libgstcodecctrl.so' 9 | 10 | # Names of this library. 11 | library_names='libgstcodecctrl.so libgstcodecctrl.so libgstcodecctrl.so' 12 | 13 | # The name of the static archive. 14 | old_library='' 15 | 16 | # Linker flags that cannot go in dependency_libs. 17 | inherited_linker_flags='' 18 | 19 | # Libraries that this one depends upon. 20 | dependency_libs=' -lgstvideo-1.0 -lgstcontroller-1.0 -lgstaudio-1.0 -lgstrtp-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0' 21 | 22 | # Names of additional weak libraries provided by this library 23 | weak_library_names='' 24 | 25 | # Version information for libgstcodecctrl. 26 | current=0 27 | age=0 28 | revision=0 29 | 30 | # Is this an already installed library? 31 | installed=yes 32 | 33 | # Should we warn about portability when linking against -modules? 34 | shouldnotlink=yes 35 | 36 | # Files to dlopen/dlpreopen 37 | dlopen='' 38 | dlpreopen='' 39 | 40 | # Directory that this library needs to be installed in: 41 | libdir='/usr/local/lib/gstreamer-1.0' 42 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/src/.libs/libgstcodecctrl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/multicam/sender/gst-codec-ctrl/gst-plugin/src/.libs/libgstcodecctrl.so -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/src/Makefile.am: -------------------------------------------------------------------------------- 1 | # Note: plugindir is set in configure 2 | 3 | ############################################################################## 4 | # TODO: change libgstplugin.la to something else, e.g. libmysomething.la # 5 | ############################################################################## 6 | plugin_LTLIBRARIES = libgstcodecctrl.la 7 | 8 | ############################################################################## 9 | # TODO: for the next set of variables, name the prefix if you named the .la, # 10 | # e.g. libmysomething.la => libmysomething_la_SOURCES # 11 | # libmysomething_la_CFLAGS # 12 | # libmysomething_la_LIBADD # 13 | # libmysomething_la_LDFLAGS # 14 | ############################################################################## 15 | 16 | ## Plugin 1 17 | 18 | # sources used to compile this plug-in 19 | libgstcodecctrl_la_SOURCES = gstcodecctrl.cpp 20 | 21 | # compiler and linker flags used to compile this plugin, set in configure.ac 22 | libgstcodecctrl_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) 23 | libgstcodecctrl_la_CXXFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CXXFLAGS) 24 | libgstcodecctrl_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-1.0 $(GST_LIBS) $(OPENH264_LIBS) 25 | libgstcodecctrl_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) 26 | libgstcodecctrl_la_LIBTOOLFLAGS = --tag=disable-static 27 | INCLUDES=-I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include/ 28 | 29 | # headers we need but don't want installed 30 | noinst_HEADERS = gstcodecctrl.h 31 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/src/gstcodecctrl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GStreamer 3 | * Copyright (C) 2005 Thomas Vander Stichele 4 | * Copyright (C) 2005 Ronald S. Bultje 5 | * Copyright (C) 2018 <> 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a 8 | * copy of this software and associated documentation files (the "Software"), 9 | * to deal in the Software without restriction, including without limitation 10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | * and/or sell copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | * DEALINGS IN THE SOFTWARE. 24 | * 25 | * Alternatively, the contents of this file may be used under the 26 | * GNU Lesser General Public License Version 2.1 (the "LGPL"), in 27 | * which case the following provisions apply instead of the ones 28 | * mentioned above: 29 | * 30 | * This library is free software; you can redistribute it and/or 31 | * modify it under the terms of the GNU Library General Public 32 | * License as published by the Free Software Foundation; either 33 | * version 2 of the License, or (at your option) any later version. 34 | * 35 | * This library is distributed in the hope that it will be useful, 36 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 38 | * Library General Public License for more details. 39 | * 40 | * You should have received a copy of the GNU Library General Public 41 | * License along with this library; if not, write to the 42 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 43 | * Boston, MA 02111-1307, USA. 44 | */ 45 | 46 | #ifndef __GST_CODECCTRL_H__ 47 | #define __GST_CODECCTRL_H__ 48 | 49 | #include 50 | #include 51 | 52 | 53 | G_BEGIN_DECLS 54 | 55 | /* #defines don't like whitespacey bits */ 56 | #define GST_TYPE_CODECCTRL \ 57 | (gst_g_codecctrl_get_type()) 58 | #define GST_CODECCTRL(obj) \ 59 | (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CODECCTRL,GstCodecCtrl)) 60 | #define GST_CODECCTRL_CLASS(klass) \ 61 | (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CODECCTRL,GstCodecCtrlClass)) 62 | #define GST_IS_CODECCTRL(obj) \ 63 | (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CODECCTRL)) 64 | #define GST_IS_CODECCTRL_CLASS(klass) \ 65 | (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CODECCTRL)) 66 | 67 | typedef struct _GstCodecCtrl GstCodecCtrl; 68 | typedef struct _GstCodecCtrlClass GstCodecCtrlClass; 69 | 70 | struct _GstCodecCtrl 71 | { 72 | GstElement element; 73 | 74 | GstPad *sinkpad, *srcpad; 75 | 76 | gboolean silent; 77 | 78 | GstElement *encoder; 79 | GstClockID clockId; 80 | 81 | guint media_src; 82 | guint ctrl_port; 83 | }; 84 | 85 | struct _GstCodecCtrlClass 86 | { 87 | GstElementClass parent_class; 88 | }; 89 | 90 | GType gst_g_codecctrl_get_type (void); 91 | 92 | static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", 93 | GST_PAD_SINK, 94 | GST_PAD_ALWAYS, 95 | GST_STATIC_CAPS ("ANY") 96 | ); 97 | 98 | static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", 99 | GST_PAD_SRC, 100 | GST_PAD_ALWAYS, 101 | GST_STATIC_CAPS ("ANY") 102 | ); 103 | 104 | static void task_print_loop(); 105 | 106 | 107 | #define gst_g_codecctrl_parent_class parent_class 108 | G_DEFINE_TYPE (GstCodecCtrl, gst_g_codecctrl, GST_TYPE_ELEMENT); 109 | 110 | static void gst_g_codecctrl_set_property (GObject * object, guint prop_id, 111 | const GValue * value, GParamSpec * pspec); 112 | static void gst_g_codecctrl_get_property (GObject * object, guint prop_id, 113 | GValue * value, GParamSpec * pspec); 114 | 115 | static gboolean gst_g_codecctrl_sink_event (GstPad * pad, GstObject * parent, GstEvent * event); 116 | static GstFlowReturn gst_g_codecctrl_chain (GstPad * pad, GstObject * parent, GstBuffer * buf); 117 | 118 | 119 | G_END_DECLS 120 | 121 | 122 | #endif /* __GST_CODECCTRL_H__ */ 123 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/src/gstplugin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GStreamer 3 | * Copyright (C) 2005 Thomas Vander Stichele 4 | * Copyright (C) 2005 Ronald S. Bultje 5 | * Copyright (C) YEAR AUTHOR_NAME AUTHOR_EMAIL 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a 8 | * copy of this software and associated documentation files (the "Software"), 9 | * to deal in the Software without restriction, including without limitation 10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | * and/or sell copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | * DEALINGS IN THE SOFTWARE. 24 | * 25 | * Alternatively, the contents of this file may be used under the 26 | * GNU Lesser General Public License Version 2.1 (the "LGPL"), in 27 | * which case the following provisions apply instead of the ones 28 | * mentioned above: 29 | * 30 | * This library is free software; you can redistribute it and/or 31 | * modify it under the terms of the GNU Library General Public 32 | * License as published by the Free Software Foundation; either 33 | * version 2 of the License, or (at your option) any later version. 34 | * 35 | * This library is distributed in the hope that it will be useful, 36 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 38 | * Library General Public License for more details. 39 | * 40 | * You should have received a copy of the GNU Library General Public 41 | * License along with this library; if not, write to the 42 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 43 | * Boston, MA 02111-1307, USA. 44 | */ 45 | 46 | #ifndef __GST_PLUGIN_TEMPLATE_H__ 47 | #define __GST_PLUGIN_TEMPLATE_H__ 48 | 49 | #include 50 | 51 | G_BEGIN_DECLS 52 | 53 | /* #defines don't like whitespacey bits */ 54 | #define GST_TYPE_PLUGIN_TEMPLATE \ 55 | (gst_plugin_template_get_type()) 56 | #define GST_PLUGIN_TEMPLATE(obj) \ 57 | (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLUGIN_TEMPLATE,GstPluginTemplate)) 58 | #define GST_PLUGIN_TEMPLATE_CLASS(klass) \ 59 | (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLUGIN_TEMPLATE,GstPluginTemplateClass)) 60 | #define GST_IS_PLUGIN_TEMPLATE(obj) \ 61 | (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLUGIN_TEMPLATE)) 62 | #define GST_IS_PLUGIN_TEMPLATE_CLASS(klass) \ 63 | (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLUGIN_TEMPLATE)) 64 | 65 | typedef struct _GstPluginTemplate GstPluginTemplate; 66 | typedef struct _GstPluginTemplateClass GstPluginTemplateClass; 67 | 68 | struct _GstPluginTemplate 69 | { 70 | GstElement element; 71 | 72 | GstPad *sinkpad, *srcpad; 73 | 74 | gboolean silent; 75 | }; 76 | 77 | struct _GstPluginTemplateClass 78 | { 79 | GstElementClass parent_class; 80 | }; 81 | 82 | GType gst_plugin_template_get_type (void); 83 | 84 | G_END_DECLS 85 | 86 | #endif /* __GST_PLUGIN_TEMPLATE_H__ */ 87 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/src/gsttransform.c: -------------------------------------------------------------------------------- 1 | /* 2 | * GStreamer 3 | * Copyright (C) 2006 Stefan Kost 4 | * Copyright (C) YEAR AUTHOR_NAME AUTHOR_EMAIL 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | /** 23 | * SECTION:element-plugin 24 | * 25 | * FIXME:Describe plugin here. 26 | * 27 | * 28 | * Example launch line 29 | * |[ 30 | * gst-launch -v -m fakesrc ! plugin ! fakesink silent=TRUE 31 | * ]| 32 | * 33 | */ 34 | 35 | #ifdef HAVE_CONFIG_H 36 | #include "config.h" 37 | #endif 38 | 39 | #include 40 | #include 41 | #include 42 | 43 | #include "gsttransform.h" 44 | 45 | GST_DEBUG_CATEGORY_STATIC (gst_plugin_template_debug); 46 | #define GST_CAT_DEFAULT gst_plugin_template_debug 47 | 48 | /* Filter signals and args */ 49 | enum 50 | { 51 | /* FILL ME */ 52 | LAST_SIGNAL 53 | }; 54 | 55 | enum 56 | { 57 | PROP_0, 58 | PROP_SILENT, 59 | }; 60 | 61 | /* the capabilities of the inputs and outputs. 62 | * 63 | * FIXME:describe the real formats here. 64 | */ 65 | static GstStaticPadTemplate sink_template = 66 | GST_STATIC_PAD_TEMPLATE ( 67 | "sink", 68 | GST_PAD_SINK, 69 | GST_PAD_ALWAYS, 70 | GST_STATIC_CAPS ("ANY") 71 | ); 72 | 73 | static GstStaticPadTemplate src_template = 74 | GST_STATIC_PAD_TEMPLATE ( 75 | "src", 76 | GST_PAD_SRC, 77 | GST_PAD_ALWAYS, 78 | GST_STATIC_CAPS ("ANY") 79 | ); 80 | 81 | #define gst_plugin_template_parent_class parent_class 82 | G_DEFINE_TYPE (GstPluginTemplate, gst_plugin_template, GST_TYPE_BASE_TRANSFORM); 83 | 84 | static void gst_plugin_template_set_property (GObject * object, guint prop_id, 85 | const GValue * value, GParamSpec * pspec); 86 | static void gst_plugin_template_get_property (GObject * object, guint prop_id, 87 | GValue * value, GParamSpec * pspec); 88 | 89 | static GstFlowReturn gst_plugin_template_transform_ip (GstBaseTransform * base, 90 | GstBuffer * outbuf); 91 | 92 | /* GObject vmethod implementations */ 93 | 94 | /* initialize the plugin's class */ 95 | static void 96 | gst_plugin_template_class_init (GstPluginTemplateClass * klass) 97 | { 98 | GObjectClass *gobject_class; 99 | GstElementClass *gstelement_class; 100 | 101 | gobject_class = (GObjectClass *) klass; 102 | gstelement_class = (GstElementClass *) klass; 103 | 104 | gobject_class->set_property = gst_plugin_template_set_property; 105 | gobject_class->get_property = gst_plugin_template_get_property; 106 | 107 | g_object_class_install_property (gobject_class, PROP_SILENT, 108 | g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?", 109 | FALSE, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); 110 | 111 | gst_element_class_set_details_simple (gstelement_class, 112 | "Plugin", 113 | "Generic/Filter", 114 | "FIXME:Generic Template Filter", 115 | "AUTHOR_NAME AUTHOR_EMAIL"); 116 | 117 | gst_element_class_add_pad_template (gstelement_class, 118 | gst_static_pad_template_get (&src_template)); 119 | gst_element_class_add_pad_template (gstelement_class, 120 | gst_static_pad_template_get (&sink_template)); 121 | 122 | GST_BASE_TRANSFORM_CLASS (klass)->transform_ip = 123 | GST_DEBUG_FUNCPTR (gst_plugin_template_transform_ip); 124 | 125 | /* debug category for fltering log messages 126 | * 127 | * FIXME:exchange the string 'Template plugin' with your description 128 | */ 129 | GST_DEBUG_CATEGORY_INIT (gst_plugin_template_debug, "plugin", 0, "Template plugin"); 130 | } 131 | 132 | /* initialize the new element 133 | * initialize instance structure 134 | */ 135 | static void 136 | gst_plugin_template_init (GstPluginTemplate *filter) 137 | { 138 | filter->silent = FALSE; 139 | } 140 | 141 | static void 142 | gst_plugin_template_set_property (GObject * object, guint prop_id, 143 | const GValue * value, GParamSpec * pspec) 144 | { 145 | GstPluginTemplate *filter = GST_PLUGIN_TEMPLATE (object); 146 | 147 | switch (prop_id) { 148 | case PROP_SILENT: 149 | filter->silent = g_value_get_boolean (value); 150 | break; 151 | default: 152 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 153 | break; 154 | } 155 | } 156 | 157 | static void 158 | gst_plugin_template_get_property (GObject * object, guint prop_id, 159 | GValue * value, GParamSpec * pspec) 160 | { 161 | GstPluginTemplate *filter = GST_PLUGIN_TEMPLATE (object); 162 | 163 | switch (prop_id) { 164 | case PROP_SILENT: 165 | g_value_set_boolean (value, filter->silent); 166 | break; 167 | default: 168 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 169 | break; 170 | } 171 | } 172 | 173 | /* GstBaseTransform vmethod implementations */ 174 | 175 | /* this function does the actual processing 176 | */ 177 | static GstFlowReturn 178 | gst_plugin_template_transform_ip (GstBaseTransform * base, GstBuffer * outbuf) 179 | { 180 | GstPluginTemplate *filter = GST_PLUGIN_TEMPLATE (base); 181 | 182 | if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (outbuf))) 183 | gst_object_sync_values (GST_OBJECT (filter), GST_BUFFER_TIMESTAMP (outbuf)); 184 | 185 | if (filter->silent == FALSE) 186 | g_print ("I'm plugged, therefore I'm in.\n"); 187 | 188 | /* FIXME: do something interesting here. This simply copies the source 189 | * to the destination. */ 190 | 191 | return GST_FLOW_OK; 192 | } 193 | 194 | 195 | /* entry point to initialize the plug-in 196 | * initialize the plug-in itself 197 | * register the element factories and other features 198 | */ 199 | static gboolean 200 | plugin_init (GstPlugin * plugin) 201 | { 202 | return gst_element_register (plugin, "plugin", GST_RANK_NONE, 203 | GST_TYPE_PLUGIN_TEMPLATE); 204 | } 205 | 206 | /* gstreamer looks for this structure to register plugins 207 | * 208 | * FIXME:exchange the string 'Template plugin' with you plugin description 209 | */ 210 | GST_PLUGIN_DEFINE ( 211 | GST_VERSION_MAJOR, 212 | GST_VERSION_MINOR, 213 | plugin, 214 | "Template plugin", 215 | plugin_init, 216 | VERSION, 217 | "LGPL", 218 | "GStreamer", 219 | "http://gstreamer.net/" 220 | ) 221 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/src/gsttransform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GStreamer 3 | * Copyright (C) 2006 Stefan Kost 4 | * Copyright (C) YEAR AUTHOR_NAME AUTHOR_EMAIL 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef __GST_PLUGIN_TEMPLATE_H__ 23 | #define __GST_PLUGIN_TEMPLATE_H__ 24 | 25 | #include 26 | #include 27 | 28 | G_BEGIN_DECLS 29 | 30 | #define GST_TYPE_PLUGIN_TEMPLATE \ 31 | (gst_plugin_template_get_type()) 32 | #define GST_PLUGIN_TEMPLATE(obj) \ 33 | (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLUGIN_TEMPLATE,GstPluginTemplate)) 34 | #define GST_PLUGIN_TEMPLATE_CLASS(klass) \ 35 | (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLUGIN_TEMPLATE,GstPluginTemplateClass)) 36 | #define GST_IS_PLUGIN_TEMPLATE(obj) \ 37 | (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLUGIN_TEMPLATE)) 38 | #define GST_IS_PLUGIN_TEMPLATE_CLASS(klass) \ 39 | (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLUGIN_TEMPLATE)) 40 | 41 | typedef struct _GstPluginTemplate GstPluginTemplate; 42 | typedef struct _GstPluginTemplateClass GstPluginTemplateClass; 43 | 44 | struct _GstPluginTemplate { 45 | GstBaseTransform element; 46 | 47 | gboolean silent; 48 | }; 49 | 50 | struct _GstPluginTemplateClass { 51 | GstBaseTransformClass parent_class; 52 | }; 53 | 54 | GType gst_plugin_template_get_type (void); 55 | 56 | G_END_DECLS 57 | 58 | #endif /* __GST_PLUGIN_TEMPLATE_H__ */ 59 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/src/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /multicam/sender/gst-codec-ctrl/gst-plugin/stamp-h1: -------------------------------------------------------------------------------- 1 | timestamp for config.h 2 | -------------------------------------------------------------------------------- /multicam/sender/killitall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | killall -9 gst-launch-1.0 scream_sender 3 | 4 | -------------------------------------------------------------------------------- /multicam/sender/scream/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | PROJECT( scream ) 4 | 5 | message("Source Dir:" ${scream_SOURCE_DIR}) 6 | 7 | SET(EXECUTABLE_OUTPUT_PATH ${scream_SOURCE_DIR}/bin) 8 | SET(LIBRARY_OUTPUT_PATH ${scream_SOURCE_DIR}/lib) 9 | SET(RUNTIME_OUTPUT_DIRECTORY ${scream_SOURCE_DIR}/bin) 10 | 11 | SET(scream_BIN ${scream_SOURCE_DIR}/bin) 12 | 13 | message("scream_SOURCE_DIR directories:" ${scream_SOURCE_DIR}) 14 | 15 | IF(UNIX) 16 | add_definitions(-std=c++0x) 17 | ENDIF(UNIX) 18 | 19 | IF(WIN32) 20 | IF(MSVC12) 21 | message("Detected MSVC12 compiler") 22 | set(MSVC_VER VC12) 23 | ELSEIF(MSVC11) 24 | message("Detected MSVC11 compiler") 25 | set(MSVC_VER VC11) 26 | ELSEIF(MSVC10) 27 | message("Detected MSVC10 compiler") 28 | set(MSVC_VER VC10) 29 | ELSEIF(MSVC14) 30 | message("Detected MSVC14 compiler") 31 | set(MSVC_VER VC14) 32 | ELSE(MSVC12) 33 | message("WARNING: Unknown/unsupported MSVC version") 34 | ENDIF(MSVC12) 35 | ENDIF(WIN32) 36 | 37 | if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) 38 | # 64bit 39 | message("Detected 64-bit build - compiling with -fPIC") 40 | SET(CMAKE_CXX_FLAGS "-fPIC -fpermissive -pthread -DV2") 41 | else( CMAKE_SIZEOF_VOID_P EQUAL 8 ) 42 | # 32 bit 43 | message("Detected 32-bit build") 44 | SET(CMAKE_CXX_FLAGS "-fpermissive -pthread -DV2") 45 | endif( CMAKE_SIZEOF_VOID_P EQUAL 8 ) 46 | 47 | #SET(LDFLAGS "-lrt -pthread -lpthread") 48 | 49 | SET(screamIncludes 50 | ${scream_SOURCE_DIR} 51 | ${scream_SOURCE_DIR}/code 52 | ) 53 | 54 | message("screamIncludes directories:" ${screamIncludes}) 55 | 56 | # lib directories 57 | IF(WIN32) 58 | SET(screamLink 59 | ${scream_SOURCE_DIR}/../lib 60 | ) 61 | ELSEIF(UNIX) 62 | SET(screamLink 63 | ${scream_SOURCE_DIR}/../lib 64 | /usr/local/lib 65 | /usr/lib 66 | ) 67 | ENDIF(WIN32) 68 | 69 | SET(LibDir 70 | ${scream_SOURCE_DIR}/../lib 71 | ) 72 | 73 | 74 | set(LIBS ${LIBS} -lrt -pthread) 75 | 76 | message("LibDir directories:" ${LibDir}) 77 | 78 | # Include directories 79 | INCLUDE_DIRECTORIES( 80 | ${scream_SOURCE_DIR}/../include 81 | ) 82 | 83 | ADD_SUBDIRECTORY( code) 84 | -------------------------------------------------------------------------------- /multicam/sender/scream/code/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # source files 2 | SET(SRCS 3 | ../../../../code/RtpQueue.cpp 4 | ../../../../code/ScreamTx.cpp 5 | ../../../../code/ScreamV2Tx.cpp 6 | ../../../../code/ScreamV2TxStream.cpp 7 | scream_sender.cpp 8 | ) 9 | 10 | SET(HEADERS 11 | ../../../../code/RtpQueue.h 12 | ../../../../code/ScreamTx.h 13 | ) 14 | 15 | SET(SRC_1 16 | ${SRCS} 17 | scream_sender.cpp 18 | ) 19 | 20 | INCLUDE_DIRECTORIES( 21 | ${screamIncludes} 22 | ../../../../code/ 23 | ) 24 | 25 | LINK_DIRECTORIES( 26 | ${screamLink} 27 | ) 28 | 29 | ADD_EXECUTABLE(scream_sender ${SRC_1} ${HEADERS}) 30 | 31 | 32 | TARGET_LINK_LIBRARIES ( 33 | scream_sender 34 | ${screamLibs} 35 | ) 36 | -------------------------------------------------------------------------------- /multicam/sender/startsender.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # The semder side processing is illustrated below 4 | # Each gstreamer pipeline encodes media and sends it on local 5 | # ports 30000 and 30002 to the SCReAM sender 6 | # The SCReAM sender implements the congestion control 7 | # and prioritization between media 8 | # and sends the multiplexed RTP media over port UDP_PORT_VIDEO to the destination, 9 | # RTCP feedback from the destinaton is also received on port UDP_PORT_VIDEO 10 | # 11 | # +-----------------+ Lo:30001 +---------------------+ 12 | # | +<----------+ | 13 | # | /dev/video0 | | | 14 | # | capture/encode +---------->+ | 15 | # +-----------------+ Lo:30000 | +-------------------> 16 | # | SCReAM sender | DST_IP:51000 17 | # +-----------------+ Lo:30003 | +<------------------- 18 | # | +<----------+ | 19 | # | /dev/video1 | | | 20 | # | capture/encode +---------->+ | 21 | # +-----------------+ Lo:30002 +---------------------+ 22 | 23 | 24 | # Set path to codecctrl plugin 25 | export GST_PLUGIN_PATH=/usr/local/lib/gstreamer-1.0/ 26 | 27 | # Settings for video encoding and streaming 28 | RECEIVER_IP=192.168.1.20 #Change to applicable receiver address 29 | UDP_PORT_VIDEO=51000 30 | NETWORK_QUEUE_DELAY_TARGET=0.06 31 | MAX_TOTAL_RATE=60000 32 | 33 | # Select type of camera here 34 | #SOURCE="e-CAM50_CUNX" 35 | SOURCE="Raspberry-Pi-HQ_Camera_12MP" 36 | #SOURCE="Movie" 37 | #SCREAM_VERSION="V1" 38 | SCREAM_VERSION="V2" 39 | 40 | 41 | if [ "$SOURCE" == "e-CAM50_CUNX" ]; then 42 | echo "Starting e-CAM50_CUNX camera(s)" 43 | 44 | # Settings for exposure compensation and sharpness 45 | # for low light condition this can be set to 8000 and 0 to 46 | # maintain full framerate 47 | EXPOSURE_COMPENSATION=140000 #default 140000 48 | SHARPNESS=16 #default 16 49 | 50 | --set-ctrl=low_latency_mode=1 --set-ctrl=exposure_compensation=$EXPOSURE_COMPENSATION --set-ctrl=sharpness=$SHARPNESS 51 | v4l2-ctl -d /dev/video1 --set-ctrl=low_latency_mode=1 --set-ctrl=exposure_compensation=$EXPOSURE_COMPENSATION --set-ctrl=sharpness=$SHARPNESS 52 | 53 | echo "Start gstreamer pipelines" 54 | 55 | ## /dev/video0 56 | # encode at 1920*1080, run application ecam_tk1_guvcview for other alternatives 57 | gst-launch-1.0 rtpbin name=rtpbin nvv4l2camerasrc device=/dev/video0 ! "video/x-raw(memory:NVMM), format=(string)UYVY, width=(int)1920, height=(int)1080" ! nvvidconv ! "video/x-raw(memory:NVMM),format=(string)I420" ! nvv4l2h264enc name=video iframeinterval=500 control-rate=1 bitrate=1000000 insert-sps-pps=true preset-level=1 profile=2 maxperf-enable=true EnableTwopassCBR=true vbv-size=500000 poc-type=2 ! queue max-size-buffers=2 ! rtph264pay mtu=1300 ! codecctrl media-src=4 port=30001 ! udpsink host=127.0.0.1 port=30000 & 58 | 59 | sleep 1 60 | ## /dev/video1 61 | gst-launch-1.0 rtpbin name=rtpbin nvv4l2camerasrc device=/dev/video1 ! "video/x-raw(memory:NVMM), format=(string)UYVY, width=(int)1920, height=(int)1080" ! nvvidconv ! nvv4l2h264enc name=video iframeinterval=500 control-rate=1 bitrate=1000000 insert-sps-pps=true preset-level=1 profile=2 maxperf-enable=true EnableTwopassCBR=true vbv-size=500000 poc-type=2 ! queue max-size-buffers=2 ! rtph264pay mtu=1300 ! codecctrl media-src=4 port=30003 ! udpsink host=127.0.0.1 port=30002 & 62 | fi 63 | 64 | if [ "$SOURCE" == "Raspberry-Pi-HQ_Camera_12MP" ]; then 65 | echo "Raspberry Pi HQ Camera 12MP camera(s)" 66 | 67 | gst-launch-1.0 rtpbin name=rtpbin nvarguscamerasrc sensor-id=0 saturation=0.5 tnr_mode=2 ee-mode=0 tnr_strength=0.1 wbmode=4 exposurecompensation=0.6 ! "video/x-raw(memory:NVMM),width=1920,height=1080,framerate=60/1" ! nvvidconv ! "video/x-raw(memory:NVMM),format=(string)I420" ! nvv4l2h264enc name=video iframeinterval=500 control-rate=1 bitrate=1000000 insert-sps-pps=true preset-level=1 profile=2 maxperf-enable=true EnableTwopassCBR=true vbv-size=500000 poc-type=2 ! queue max-size-buffers=2 ! rtph264pay mtu=1300 ! codecctrl media-src=4 port=30001 ! udpsink host=127.0.0.1 port=30000 & 68 | 69 | gst-launch-1.0 rtpbin name=rtpbin nvarguscamerasrc sensor-id=1 saturation=0.6 tnr_mode=2 ee-mode=0 tnr_strength=0.1 ! "video/x-raw(memory:NVMM),width=1920,height=1080,framerate=60/1" ! nvvidconv ! "video/x-raw(memory:NVMM),format=(string)I420" ! nvv4l2h264enc name=video iframeinterval=500 control-rate=1 bitrate=1000000 insert-sps-pps=true preset-level=1 profile=2 maxperf-enable=true EnableTwopassCBR=true vbv-size=500000 poc-type=2 ! queue max-size-buffers=2 ! rtph264pay mtu=1300 ! codecctrl media-src=4 port=30003 ! udpsink host=127.0.0.1 port=30002 & 70 | fi 71 | 72 | if [ "$SOURCE" == "Movie" ]; then 73 | # Download the big buck bunny 1080p60fps movie 74 | # from http://ftp.vim.org/ftp/ftp/pub/graphics/blender/demo/movies/BBB/ 75 | MEDIA=~/bbb_sunflower_1080p_60fps_normal.mp4 76 | gst-launch-1.0 rtpbin name=rtpbin multifilesrc location=$MEDIA location=$MEDIA loop=true stop-index=-1 ! qtdemux name=demux ! queue ! h264parse ! omxh264dec ! queue ! nvv4l2h264enc name=video iframeinterval=500 control-rate=1 bitrate=1000000 insert-sps-pps=true preset-level=1 profile=2 maxperf-enable=true EnableTwopassCBR=true vbv-size=500000 poc-type=2 ! queue max-size-buffers=2 ! rtph264pay mtu=1300 ! codecctrl media-src=4 port=30001 ! udpsink host=127.0.0.1 port=30000 & 77 | fi 78 | 79 | sleep 1 80 | ##Start SCReAM sender side. 81 | # The rate control is configured so that /dev/video0 gets a higher prority (1.0) 82 | # while /dev/video1 gets a lower priority (0.5), see -priority parameter 83 | # Min, max and init rate for /dev/video{0,1} can also be configured 84 | # ratescale compensates for offset that may occur between target and actual bitrates for the video coder 85 | # For L4S capability, change to 86 | # ./screamTx/bin/scream_sender -ect 1 87 | 88 | echo "Video streaming started" 89 | if [ "$SCREAM_VERSION" == "V1" ]; then 90 | ./scream/bin/scream_sender -ect 1 -delaytarget $NETWORK_QUEUE_DELAY_TARGET -priority 1.0:0.5 -ratemax 25000:25000 -ratemin 2000:2000 -rateinit 5000:5000 -ratescale 1.0:1.0 -cwvmem 60 -maxtotalrate $MAX_TOTAL_RATE -pacingheadroom 1.2 2 $RECEIVER_IP $UDP_PORT_VIDEO & 91 | fi 92 | if [ "$SCREAM_VERSION" == "V2" ]; then 93 | ./scream/bin/scream_sender -ect 1 -delaytarget $NETWORK_QUEUE_DELAY_TARGET -priority 1.0:0.5 -ratemax 25000:25000 -ratemin 2000:2000 -rateinit 5000:5000 -ratescale 1.0:1.0 -maxtotalrate $MAX_TOTAL_RATE -pacingheadroom 1.5 2 $RECEIVER_IP $UDP_PORT_VIDEO & 94 | fi 95 | -------------------------------------------------------------------------------- /multicam/sender/startsender_2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # The semder side processing is illustrated below 4 | # Each gstreamer pipeline encodes media and sends it on local 5 | # ports 30000 and 30002 to the SCReAM sender 6 | # The SCReAM sender implements the congestion control 7 | # and prioritization between media 8 | # and sends the multiplexed RTP media over port UDP_PORT_VIDEO to the destination, 9 | # RTCP feedback from the destinaton is also received on port UDP_PORT_VIDEO 10 | # 11 | # +-----------------+ Lo:30001 +---------------------+ 12 | # | +<----------+ | 13 | # | /dev/video0 | | | 14 | # | capture/encode +---------->+ | 15 | # +-----------------+ Lo:30000 | +-------------------> 16 | # | SCReAM sender | DST_IP:51000 17 | # +-----------------+ Lo:30003 | +<------------------- 18 | # | +<----------+ | 19 | # | /dev/video1 | | | 20 | # | capture/encode +---------->+ | 21 | # +-----------------+ Lo:30002 +---------------------+ 22 | 23 | 24 | # Set path to codecctrl plugin 25 | export GST_PLUGIN_PATH=/usr/local/lib/gstreamer-1.0/ 26 | 27 | # Settings for video encoding and streaming 28 | RECEIVER_IP=192.168.1.20 #Change to applicable receiver address 29 | UDP_PORT_VIDEO=51000 30 | NETWORK_QUEUE_DELAY_TARGET=0.06 31 | MAX_TOTAL_RATE=60000 32 | 33 | # Select type of camera here 34 | #SOURCE="e-CAM50_CUNX" 35 | SOURCE="Raspberry-Pi-HQ_Camera_12MP" 36 | SOURCE="Movie" 37 | #SCREAM_VERSION="V1" 38 | SCREAM_VERSION="V2" 39 | 40 | 41 | if [ "$SOURCE" == "e-CAM50_CUNX" ]; then 42 | echo "Starting e-CAM50_CUNX camera(s)" 43 | 44 | # Settings for exposure compensation and sharpness 45 | # for low light condition this can be set to 8000 and 0 to 46 | # maintain full framerate 47 | EXPOSURE_COMPENSATION=140000 #default 140000 48 | SHARPNESS=16 #default 16 49 | 50 | --set-ctrl=low_latency_mode=1 --set-ctrl=exposure_compensation=$EXPOSURE_COMPENSATION --set-ctrl=sharpness=$SHARPNESS 51 | v4l2-ctl -d /dev/video1 --set-ctrl=low_latency_mode=1 --set-ctrl=exposure_compensation=$EXPOSURE_COMPENSATION --set-ctrl=sharpness=$SHARPNESS 52 | 53 | echo "Start gstreamer pipelines" 54 | 55 | ## /dev/video0 56 | # encode at 1920*1080, run application ecam_tk1_guvcview for other alternatives 57 | gst-launch-1.0 rtpbin name=rtpbin nvv4l2camerasrc device=/dev/video0 ! "video/x-raw(memory:NVMM), format=(string)UYVY, width=(int)1920, height=(int)1080" ! nvvidconv ! "video/x-raw(memory:NVMM),format=(string)I420" ! nvv4l2h264enc name=video iframeinterval=500 control-rate=1 bitrate=1000000 insert-sps-pps=true preset-level=1 profile=2 maxperf-enable=true EnableTwopassCBR=true vbv-size=500000 poc-type=2 ! queue max-size-buffers=2 ! rtph264pay mtu=1300 ! codecctrl media-src=4 port=30001 ! udpsink host=127.0.0.1 port=30000 & 58 | 59 | sleep 1 60 | ## /dev/video1 61 | gst-launch-1.0 rtpbin name=rtpbin nvv4l2camerasrc device=/dev/video1 ! "video/x-raw(memory:NVMM), format=(string)UYVY, width=(int)1920, height=(int)1080" ! nvvidconv ! nvv4l2h264enc name=video iframeinterval=500 control-rate=1 bitrate=1000000 insert-sps-pps=true preset-level=1 profile=2 maxperf-enable=true EnableTwopassCBR=true vbv-size=500000 poc-type=2 ! queue max-size-buffers=2 ! rtph264pay mtu=1300 ! codecctrl media-src=4 port=30003 ! udpsink host=127.0.0.1 port=30002 & 62 | fi 63 | 64 | if [ "$SOURCE" == "Raspberry-Pi-HQ_Camera_12MP" ]; then 65 | echo "Raspberry Pi HQ Camera 12MP camera(s)" 66 | 67 | gst-launch-1.0 rtpbin name=rtpbin nvarguscamerasrc sensor-id=0 saturation=0.5 tnr_mode=2 ee-mode=0 tnr_strength=0.1 wbmode=4 exposurecompensation=0.7 ! "video/x-raw(memory:NVMM),width=1920,height=1080,framerate=50/1" ! nvvidconv ! "video/x-raw(memory:NVMM),format=(string)I420" ! nvv4l2h264enc name=video iframeinterval=500 control-rate=1 bitrate=1000000 insert-sps-pps=true preset-level=1 profile=2 maxperf-enable=true EnableTwopassCBR=true vbv-size=500000 poc-type=2 ! queue max-size-buffers=2 ! rtph264pay mtu=1300 ! codecctrl media-src=4 port=30001 ! udpsink host=127.0.0.1 port=30000 & 68 | 69 | gst-launch-1.0 rtpbin name=rtpbin nvarguscamerasrc sensor-id=1 saturation=0.6 tnr_mode=2 ee-mode=0 tnr_strength=0.1 ! "video/x-raw(memory:NVMM),width=1920,height=1080,framerate=60/1" ! nvvidconv ! "video/x-raw(memory:NVMM),format=(string)I420" ! nvv4l2h264enc name=video iframeinterval=500 control-rate=1 bitrate=1000000 insert-sps-pps=true preset-level=1 profile=2 maxperf-enable=true EnableTwopassCBR=true vbv-size=500000 poc-type=2 ! queue max-size-buffers=2 ! rtph264pay mtu=1300 ! codecctrl media-src=4 port=30003 ! udpsink host=127.0.0.1 port=30002 & 70 | fi 71 | 72 | if [ "$SOURCE" == "Movie" ]; then 73 | # Download the big buck bunny 1080p60fps movie 74 | # from http://ftp.vim.org/ftp/ftp/pub/graphics/blender/demo/movies/BBB/ 75 | MEDIA=~/bbb_sunflower_1080p_60fps_normal.mp4 76 | gst-launch-1.0 rtpbin name=rtpbin multifilesrc location=$MEDIA location=$MEDIA loop=true stop-index=-1 ! qtdemux name=demux ! queue ! h264parse ! omxh264dec ! queue ! nvv4l2h264enc name=video iframeinterval=500 control-rate=1 bitrate=1000000 insert-sps-pps=true preset-level=1 profile=2 maxperf-enable=true EnableTwopassCBR=true vbv-size=500000 poc-type=2 ! queue max-size-buffers=2 ! rtph264pay mtu=1300 ! codecctrl media-src=4 port=30001 ! udpsink host=127.0.0.1 port=30000 & 77 | fi 78 | 79 | sleep 1 80 | ##Start SCReAM sender side. 81 | # The rate control is configured so that /dev/video0 gets a higher prority (1.0) 82 | # while /dev/video1 gets a lower priority (0.5), see -priority parameter 83 | # Min, max and init rate for /dev/video{0,1} can also be configured 84 | # ratescale compensates for offset that may occur between target and actual bitrates for the video coder 85 | # For L4S capability, change to 86 | # ./screamTx/bin/scream_sender -ect 1 87 | 88 | echo "Video streaming started" 89 | if [ "$SCREAM_VERSION" == "V1" ]; then 90 | ./scream/bin/scream_sender -ect 1 -delaytarget $NETWORK_QUEUE_DELAY_TARGET -priority 1.0:0.5 -ratemax 25000:25000 -ratemin 2000:2000 -rateinit 5000:5000 -ratescale 1.0:1.0 -cwvmem 60 -maxtotalrate $MAX_TOTAL_RATE -pacingheadroom 1.2 2 $RECEIVER_IP $UDP_PORT_VIDEO & 91 | fi 92 | if [ "$SCREAM_VERSION" == "V2" ]; then 93 | ./scream/bin/scream_sender -ect 1 -delaytarget $NETWORK_QUEUE_DELAY_TARGET -priority 1.0:0.5 -ratemax 25000:25000 -ratemin 2000:2000 -rateinit 5000:5000 -ratescale 1.0:1.0 -maxtotalrate $MAX_TOTAL_RATE -pacingheadroom 1.5 2 $RECEIVER_IP $UDP_PORT_VIDEO & 94 | fi 95 | -------------------------------------------------------------------------------- /plot_1_stream.m: -------------------------------------------------------------------------------- 1 | function plot_1_stream(a,Tlim,maxR,maxD,maxRT, U) 2 | % Plot stdout for 1-streaming 3 | % script is adapted to 1 stream 4 | % Tlim [min max] time e.g [0 1000] 5 | % maxR max rate [Mbps] 6 | % maxD max delay [s] 7 | % example: 8 | % >a = load('logfile.txt'); 9 | % >plot_vay_4(a,[0 1000],15,0.1); 10 | 11 | T=a(:,1);T=T-T(1); 12 | 13 | B = ones(1,U)/U; 14 | K=6;L=1; 15 | subplot(K,1,L);L=L+1; 16 | %plot(T,a(:,4)/1e3,T,a(:,5)/1e3,':',T,a(:,7)*max(a(:,4))/1e3*0.05,':k'); 17 | plot(T,a(:,4)/1200,T,a(:,5)/1200,':'); 18 | set(gca,'FontSize',12);grid on; 19 | %title('CWND and bytes in flight [kbyte]') 20 | title('CWND and bytes in flight [MSS]') 21 | set(gca,'XTickLabel',[]); 22 | xlim(Tlim); 23 | 24 | subplot(K,1,L);L=L+1; 25 | plot(T,a(:,2),T,a(:,3)); 26 | set(gca,'FontSize',12);grid on; 27 | set(gca,'XTickLabel',[]); 28 | title('Est. queue delay and RTT [s]') 29 | ylim([0 maxD]); 30 | xlim(Tlim); 31 | 32 | subplot(K,1,L);L=L+1; 33 | plot(T,a(:,8)+a(:,2)); 34 | set(gca,'FontSize',12);grid on; 35 | set(gca,'XTickLabel',[]); 36 | title('RTP queue+network delay[s]') 37 | ylim([0 maxD]); 38 | xlim(Tlim); 39 | 40 | subplot(K,1,L);L=L+1; 41 | ce = a(:,13); 42 | loss = a(:,12); 43 | plot(T,ce/1e3,T,loss/1e3,T,filter(B,1,a(:,6))/1e3,'k'); 44 | set(gca,'FontSize',12);grid on; 45 | set(gca,'XTickLabel',[]); 46 | title('Tx rate [Mbps]') 47 | legend('ce','loss','Total') 48 | ylim([0 maxRT]); 49 | xlim(Tlim); 50 | 51 | subplot(K,1,L);L=L+1; 52 | plot(T,a(:,9)/1e3); 53 | set(gca,'FontSize',12);grid on; 54 | set(gca,'XTickLabel',[]); 55 | xlim(Tlim); 56 | ylim([0 maxR]); 57 | title('Target rate [Mbps]') 58 | 59 | subplot(K,1,L);L=L+1; 60 | plot(T,filter(B,1,a(:,10))/1e3); 61 | set(gca,'FontSize',12);grid on; 62 | title('Encoder rate [Mbps]') 63 | xlim(Tlim); 64 | ylim([0 maxR]); 65 | xlabel('T [s]') 66 | 67 | end -------------------------------------------------------------------------------- /plot_1_stream_s.m: -------------------------------------------------------------------------------- 1 | function plot_1_streams(a,Tlim,maxR,maxD,maxRT, U) 2 | % Plot stdout for 1-streaming 3 | % script is adapted to 1 stream 4 | % Tlim [min max] time e.g [0 1000] 5 | % maxR max rate [Mbps] 6 | % maxD max delay [s] 7 | % example: 8 | % >a = load('logfile.txt'); 9 | % >plot_vay_4(a,[0 1000],15,0.1); 10 | 11 | T=a(:,1);T=T-T(1); 12 | 13 | B = ones(1,U)/U; 14 | K=4;L=1; 15 | subplot(K,1,L);L=L+1; 16 | %plot(T,a(:,4)/1e3,T,a(:,5)/1e3,':',T,a(:,7)*max(a(:,4))/1e3*0.05,':k'); 17 | plot(T,a(:,4)/1200,T,a(:,5)/1200,':'); 18 | set(gca,'FontSize',12);grid on; 19 | %title('CWND and bytes in flight [kbyte]') 20 | title('CWND and bytes in flight [MSS]') 21 | set(gca,'XTickLabel',[]); 22 | xlim(Tlim); 23 | 24 | subplot(K,1,L);L=L+1; 25 | plot(T,a(:,2),T,a(:,3)); 26 | set(gca,'FontSize',12);grid on; 27 | set(gca,'XTickLabel',[]); 28 | title('Est. queue delay and RTT [s]') 29 | ylim([0 maxD]); 30 | xlim(Tlim); 31 | 32 | subplot(K,1,L);L=L+1; 33 | plot(T,a(:,8)); 34 | set(gca,'FontSize',12);grid on; 35 | set(gca,'XTickLabel',[]); 36 | title('RTP queue delay[s]') 37 | ylim([0 maxD]); 38 | xlim(Tlim); 39 | 40 | subplot(K,1,L);L=L+1; 41 | ce = a(:,13); 42 | loss = a(:,12); 43 | plot(T,filter(B,1,a(:,6))/1e3,'k'); 44 | set(gca,'FontSize',12);grid on; 45 | title('Tx rate [Mbps]') 46 | ylim([0 maxRT]); 47 | xlim(Tlim); 48 | 49 | xlabel('T [s]') 50 | 51 | end -------------------------------------------------------------------------------- /plot_4_stream.m: -------------------------------------------------------------------------------- 1 | function plot_4_stream(a,Tlim,maxR,maxD,maxRT, U) 2 | % Plot stdout for 4-streaming 3 | % script is adapted to 4 streams 4 | % Tlim [min max] time e.g [0 1000] 5 | % maxR max rate [Mbps] 6 | % maxD max delay [s] 7 | % example: 8 | % >a = load('logfile.txt'); 9 | % >plot_vay_4(a,[0 1000],15,0.1); 10 | 11 | T=a(:,1);T=T-T(1); 12 | 13 | B = ones(1,U)/U; 14 | K=7;L=1; 15 | subplot(K,1,L);L=L+1; 16 | plot(T,a(:,4)/1e3,T,a(:,5)/1e3,':',T,a(:,7)*max(a(:,4))/1e3*0.05,':k'); 17 | set(gca,'FontSize',12);grid on; 18 | title('CWND and bytes in flight [kbyte]') 19 | set(gca,'XTickLabel',[]); 20 | xlim(Tlim); 21 | 22 | subplot(K,1,L);L=L+1; 23 | plot(T,a(:,2),T,a(:,3)); 24 | set(gca,'FontSize',12);grid on; 25 | set(gca,'XTickLabel',[]); 26 | title('Est. queue delay and RTT [s]') 27 | ylim([0 maxD]); 28 | xlim(Tlim); 29 | 30 | subplot(K,1,L);L=L+1; 31 | plot(T,a(:,8),T,a(:,8+6),T,a(:,8+12),T,a(:,8+18)); 32 | set(gca,'FontSize',12);grid on; 33 | set(gca,'XTickLabel',[]); 34 | legend('0','1','2','3') 35 | title('RTP queue delay[s]') 36 | ylim([0 maxD]); 37 | xlim(Tlim); 38 | 39 | subplot(K,1,L);L=L+1; 40 | ce = a(:,13)+a(:,13+6)+a(:,13+12)+a(:,13+18); 41 | loss = a(:,12)+a(:,12+6)+a(:,12+12)+a(:,12+18); 42 | plot(T,ce/1e2,T,loss/1e2,T,filter(B,1,a(:,6))/1e3,'k'); 43 | set(gca,'FontSize',12);grid on; 44 | set(gca,'XTickLabel',[]); 45 | title('Tx rate [Mbps]') 46 | legend('ce*10','loss*10','Total') 47 | ylim([0 maxRT]); 48 | xlim(Tlim); 49 | 50 | subplot(K,1,L);L=L+1; 51 | plot(T,filter(B,1,a(:,11))/1e3,T,filter(B,1,a(:,11+6))/1e3,T,filter(B,1,a(:,11+12))/1e3,T,filter(B,1,a(:,11+18))/1e3); 52 | set(gca,'FontSize',12);grid on; 53 | set(gca,'XTickLabel',[]); 54 | title('Tx rate streams [Mbps]') 55 | legend('0','1','2','3') 56 | ylim([0 maxR]); 57 | xlim(Tlim); 58 | 59 | subplot(K,1,L);L=L+1; 60 | plot(T,a(:,9)/1e3,'-',T,a(:,9+6)/1e3,'-',T,a(:,9+12)/1e3,'-',T,a(:,9+18)/1e3,'-'); 61 | set(gca,'FontSize',12);grid on; 62 | set(gca,'XTickLabel',[]); 63 | legend('0','1','2','3') 64 | xlim(Tlim); 65 | ylim([0 maxR]); 66 | title('Target rate [Mbps]') 67 | 68 | subplot(K,1,L);L=L+1; 69 | plot(T,filter(B,1,a(:,10))/1e3,T,filter(B,1,a(:,10+6))/1e3,T,filter(B,1,a(:,10+12))/1e3,T,filter(B,1,a(:,10+18))/1e3); 70 | set(gca,'FontSize',12);grid on; 71 | legend('0','1','2','3') 72 | title('Encoder rate [Mbps]') 73 | xlim(Tlim); 74 | ylim([0 maxR]); 75 | xlabel('T [s]') 76 | 77 | end -------------------------------------------------------------------------------- /plot_cdf.m: -------------------------------------------------------------------------------- 1 | function plot_cdf(a,Tlim,Tmax) 2 | % This function plots the CDF of the RTT and 3 | % queue delay from the logs given by the 4 | % SCReAM BW test tool. 5 | % Parameters : 6 | % a : log file from SCReAM BW test tool 7 | % imported with the command 8 | % a = load(); 9 | % where is the name of the log file 10 | % Tlim : xmin and xmax limits [s], e.g. [0 100] 11 | % Tmax : Max displayed value for RTT/delay 12 | % 13 | % The script can be used with matlab or octave 14 | % Octave can sometimes be painfully slow. The following commands 15 | % can make it faster 16 | % >a = a = load(); 17 | % >a = a(1:50:end,:); % subsample the log file 18 | % >figure(1); 19 | % >plot_cdf(.... 20 | % 21 | 22 | T = a(:,1); 23 | ix = intersect(find(T > Tlim(1)),find(T <= Tlim(2))); 24 | 25 | qd = sort(a(ix,2)); 26 | rtt = sort(a(ix,3)); 27 | N = length(qd); N = (0:N-1)/(N-1); 28 | 29 | subplot(111); 30 | plot(qd,N,rtt,N); 31 | set(gca,'FontSize',14);grid on; 32 | title('CDF Network queue delay and RTT [s]'); 33 | legend('Queue delay','RTT'); 34 | xlim([0 Tmax]); 35 | 36 | xlabel('[s]'); 37 | end 38 | 39 | -------------------------------------------------------------------------------- /plot_thp_delay.m: -------------------------------------------------------------------------------- 1 | function plot_thp_delay(a,id,Tlim,maxThp,maxDelay) 2 | % This function plots the thorughput 3 | % RTT and estimated queue delay 4 | % Parameters: 5 | % a : log file from SCReAM BW test tool 6 | % imported with the command 7 | % a = load(); 8 | % where is the name of the log file 9 | % id : stream id 10 | % Tlim : xmin and xmax limits [s], e.g. [0 100] 11 | % maxThp : Max thorughput [Mbps] 12 | % maxDelay : Max delay [s] 13 | % 14 | % The script can be used with matlab or octave 15 | % 16 | ix = find(a(:,8)==id); 17 | 18 | T = a(ix,1); 19 | T = T-T(1); 20 | 21 | subplot(4,1,1); 22 | plot(T,filter(1,1,a(ix,13))/1e6,T,a(ix,12)/1e6,T,a(ix,14)/1e6,T,a(ix,18)/1e6,T,min(maxThp/10,a(ix,15)/1e3-1),'.k'); 23 | set(gca,'FontSize',12);grid on; 24 | set(gca,'XTickLabel',[]);grid on; 25 | title('Throughput [Mbps]'); 26 | legend('Transmitted','RTP','ACKed','Target','Loss') 27 | xlim(Tlim); 28 | ylim([0 maxThp]); 29 | 30 | subplot(4,1,2); 31 | plot(T,a(ix,5)/1e3,'-r',T,a(ix,4)/1e3,'.-b'); 32 | set(gca,'FontSize',12);grid on; 33 | set(gca,'XTickLabel',[]);grid on; 34 | title('CWND(B) and bytes in flight(R) [kByte]'); 35 | xlim(Tlim); 36 | 37 | subplot(4,1,3); 38 | x = a(ix,11)./a(ix,10)*100; 39 | plot(T,x); 40 | mean(x) 41 | set(gca,'FontSize',12);grid on; 42 | set(gca,'XTickLabel',[]);grid on; 43 | title('Congestion mark [%]'); 44 | xlim(Tlim); 45 | ylim([0 110]); 46 | 47 | subplot(4,1,4); 48 | plot(T,a(ix,2),'.-',T,a(ix,3),'.-','linewidth',1);ylim([0 maxDelay]); 49 | set(gca,'FontSize',12);grid on; 50 | title('Network queue(B) and RTT(R) [s]'); 51 | xlim(Tlim); 52 | 53 | xlabel('T [s]'); 54 | xlim(Tlim); 55 | end 56 | 57 | -------------------------------------------------------------------------------- /plot_thp_delay_new.m: -------------------------------------------------------------------------------- 1 | function plot_thp_delay_new(a,id,Tlim,maxThp,maxDelay) 2 | % This function plots the thorughput 3 | % RTT and estimated queue delay 4 | % Parameters: 5 | % a : log file from SCReAM BW test tool 6 | % imported with the command 7 | % a = load(); 8 | % where is the name of the log file 9 | % id * stream id 10 | % Tlim : xmin and xmax limits [s], e.g. [0 100] 11 | % maxThp : Max thorughput [Mbps] 12 | % maxDelay : Max delay [s] 13 | % 14 | % The script can be used with matlab or octave 15 | % 16 | ix = find(a(:,8)==id); 17 | 18 | T = a(ix,1); 19 | T = T-T(1); 20 | K = 10; 21 | B = ones(1,K)/K; 22 | A = [1 -0.95]; 23 | 24 | 25 | subplot(4,1,1); 26 | %plot(T,filter(1,1,a(ix,13))/1e6,T,filter(B,1,a(ix,12))/1e6,T,filter(B,1,a(ix,14))/1e6) 27 | plot(T,filter(1,1,a(ix,13))/1e6,T,filter(0.05,A,a(ix,12))/1e6,T,filter(0.05,A,a(ix,14))/1e6,T,a(ix,18)/1e6); 28 | set(gca,'FontSize',12);grid on; 29 | set(gca,'XTickLabel',[]);grid on; 30 | title('Throughput [Mbps]'); 31 | legend('Transmitted','RTP','ACKed','Target') 32 | xlim(Tlim); 33 | ylim([0 maxThp]); 34 | 35 | subplot(4,1,2); 36 | plot(T,a(ix,5)/1e3,'-R',T,a(ix,4)/1e3,'.-B'); 37 | set(gca,'FontSize',12);grid on; 38 | set(gca,'XTickLabel',[]);grid on; 39 | title('CWND(B) and bytes in flight(R) [kByte]'); 40 | xlim(Tlim); 41 | 42 | 43 | subplot(4,1,3); 44 | K = 1; 45 | B = ones(1,K)/K; 46 | x = a(ix,11)./a(ix,10)*100; 47 | plot(T,filter(B,1,x)); 48 | mean(x) 49 | set(gca,'FontSize',12);grid on; 50 | set(gca,'XTickLabel',[]);grid on; 51 | title('Congestion mark [%]'); 52 | xlim(Tlim); 53 | ylim([0 110]); 54 | 55 | 56 | K = 10; 57 | B = ones(1,K)/K; 58 | 59 | subplot(4,1,4); 60 | plot(T,a(ix,2),'.-',T,filter(B,1,a(ix,19)),'.-','linewidth',1);ylim([0 maxDelay]); 61 | %plot(T,a(ix,2)+a(ix,19),'R.',T,a(ix,2),'B.-','linewidth',1);ylim([0 maxDelay]); 62 | set(gca,'FontSize',12);grid on; 63 | title('Network queue(B) and RTP Q (R) [s]'); 64 | xlim(Tlim); 65 | 66 | 67 | xlabel('T [s]'); 68 | xlim(Tlim); 69 | end 70 | 71 | -------------------------------------------------------------------------------- /plot_txrx.m: -------------------------------------------------------------------------------- 1 | function plot_txrx(a,Tlim,maxDelay) 2 | 3 | 4 | T = a(:,1); 5 | T = T-T(1); 6 | rxtx = a(:,5); 7 | ix = find(a(:,5)>0); 8 | rxtxmin= min(rxtx(ix)); 9 | rxtx(ix) = rxtx(ix)-rxtxmin; 10 | ix = find(rxtx < 0); 11 | if length(ix) > 0 12 | plot(T,rxtx,T(ix),maxDelay/10,'ro'); 13 | else 14 | plot(T,rxtx); 15 | end 16 | grid; 17 | xlim(Tlim); ylim([0 maxDelay]); 18 | set(gca,'FontSize',12); 19 | xlabel('T[s]'); 20 | legend('RX-TX delay','Loss') 21 | title('RX-TX delay [s]'); 22 | 23 | end -------------------------------------------------------------------------------- /scream.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32811.315 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scream_01", "code\scream_01.vcxproj", "{995F8DF3-7BE9-4B48-89EA-4F64046D68C2}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {995F8DF3-7BE9-4B48-89EA-4F64046D68C2}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {995F8DF3-7BE9-4B48-89EA-4F64046D68C2}.Debug|Win32.Build.0 = Debug|Win32 16 | {995F8DF3-7BE9-4B48-89EA-4F64046D68C2}.Release|Win32.ActiveCfg = Release|Win32 17 | {995F8DF3-7BE9-4B48-89EA-4F64046D68C2}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {B20F2EED-C0EB-444F-BCAE-BE6E58364120} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /scream_ecn_keyframe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/scream_ecn_keyframe.png -------------------------------------------------------------------------------- /scream_noecn_keyframe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricssonResearch/scream/5d5e4ca2c41ad62875314e5e8d2571efd58aad6a/scream_noecn_keyframe.png -------------------------------------------------------------------------------- /test-record.md: -------------------------------------------------------------------------------- 1 | # Test activities with SCReAM 2 | Test activities ordered, most recent first 3 | 4 | ## Test activity 2024-10-31 5 | SCReAM test with 100Mbps bottleneck with DualPi2 AQM 6 | SCReAM commit 76a298add1ebd3714f86ae6f4a31194ca04a168f (2024-10-31) 7 | 8 | ### Hardware and qdisc configuration 9 | Same as 2024-10-28 10 | 11 | ### Test 2, different RTTs 12 | The test is run with 5 different values of RTT and up to 4 additional TCP loads 13 | 14 | -microburstinterval 0.5 15 | -mtu 1360 (1400 byte in IP level) 16 | -rand 0 (fixed frame sizes) 17 | 18 | | RTT [ms] | 0 TCP | 1 TCP | 2 TCP | 3 TCP | 4 TCP | 19 | | :- |:-:|:-:|:-:|:-:|:-:| 20 | | 5 | 79 | 52 | 40 | 29 | 20 | 21 | | 10 | 78 | 58 | 40 | 28 | 22 | 22 | | 25 | 78 | 60 | 48 | 38 | 29 | 23 | | 50 | 76 | 60 | 43 | 35 | 30 | 24 | | 100 | 71 | 54 | 32 | 25 | 18 | 25 | 26 | ![First 20s only SCreAM then 1 TCP Prague added every 20s](https://github.com/EricssonResearch/scream/blob/master/images/L4S-100Mbps-25ms-0-4-TCP.png) 27 | First 20s only SCreAM then 1 TCP Prague added every 20s 28 | 29 | ![First 20s only SCreAM then 4 TCP Prague for 20s](https://github.com/EricssonResearch/scream/blob/master/images/L4S-100Mbps-25ms-0-4-0-TCP.png) 30 | First 20s only SCreAM then 4 TCP Prague for 20s 31 | 32 | 33 | ### Test3, different RTTs, and varying video frame sizes 34 | Like test # 2 but varying video frame sizes 35 | 36 | -microburstinterval 0.5 37 | -mtu 1360 : 1400 byte on IP level 38 | -rand 50 : frame sizes vary +/-1 50% from the nominal (uniform distribution) 39 | 40 | | RTT [ms] | 0 TCP | 1 TCP | 2 TCP | 3 TCP | 4 TCP | 41 | | :- |:-:|:-:|:-:|:-:|:-:| 42 | | 5 | 70 | 48 | 30 | 25 | 18 | 43 | | 10 | 68 | 50 | 36 | 28 | 18 | 44 | | 25 | 68 | 50 | 44 | 32 | 25 | 45 | | 50 | 66 | 46 | 38 | 30 | 23 | 46 | | 100 | 64 | 48 | 38 | 26 | 21 | 47 | 48 | ![First 20s only SCreAM then 1 TCP Prague added every 20s](https://github.com/EricssonResearch/scream/blob/master/images/L4S-100Mbps-25ms-r-50-0-4-TCP.png) 49 | First 20s only SCreAM then 1 TCP Prague added every 20s 50 | 51 | 52 | ### Summary 53 | The results do no differ greatly from the test 2024-10-28, this means that the introduced cubic emulation with L4S gives more stable bitrate and less delay spikes and still manages to compete with TCP Prague in the given test range. 54 | SCReAM gets a larger share of the link capacity than is fair. Possibly the algorithm can be tuned a bit more conservative to trade bitrate against a even more stable behavior. 55 | 56 | 57 | ## Test activity 2024-10-28 58 | SCReAM test with 100Mbps bottleneck with DualPi2 AQM 59 | SCReAM commit 994f9a40d4b4a78b8052551e3480b30269d75a3a (2024-10-28) 60 | 61 | ### Hardware and qdisc configuration 62 | The test laptops are two Lenovo ThinkPad E470 with Ubuntu 20.04. The PCs are interconnected with an ethernet cable 63 | Linux release 5.15 with TCP Prague and DualPi2 from 64 | https://github.com/L4STeam/linux is used. Iperf is used as additional load generator, confugured to use L4S and Prague 65 | 66 | The bottleneck is configured on the receiving (client side) with the below script 67 | 68 | ~~~ 69 | # Script that runs on the receiving side to model an 70 | # L4S-capable link with 100Mbps throughput and 25ms RTT 71 | # $INTERFACE is the network interface 72 | 73 | sudo modprobe ifb numifbs=1 74 | sudo ip link set dev ifb0 up 75 | 76 | # Delete old stuff 77 | sudo tc qdisc del dev $INTERFACE root 78 | sudo tc qdisc del dev ifb0 root 79 | sudo tc qdisc del dev $INTERFACE handle ffff: ingress 80 | 81 | sudo tc qdisc add dev $INTERFACE handle ffff: ingress 82 | sudo tc filter add dev $INTERFACE parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0 83 | 84 | # Add 25ms RTT to egress interface 85 | sudo tc qdisc add dev $INTERFACE root netem delay 25ms 86 | 87 | # Ingress, limit and add L4S marking 88 | sudo tc qdisc add dev ifb0 root handle 1: htb default 10 89 | sudo tc class add dev ifb0 parent 1: classid 1:1 htb rate 100mbit ceil 100mbit 90 | sudo tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 100mbit ceil 100mbit 91 | sudo tc qdisc add dev ifb0 parent 1:10 dualpi2 92 | ~~~ 93 | 94 | 95 | The expected SCReAM bitrate [Mbps] given the number of additional TCP loads is 96 | 97 | | 0 TCP | 1 TCP | 2 TCP | 3 TCP | 4 TCP | 98 | |:-:|:-:|:-:|:-:|:-:| 99 | | 100 | 50 | 33 | 25 | 20 | 100 | 101 | All tests are run with only one iteration so one can expect a roughlt +/- 5% deviation from the figures below. 102 | 103 | ### Test 1, impact of microburst interval 104 | The test examines the impact of the microburst interval in the SCReAM performance without additional load and with 105 | -microburstinterval X 106 | -mtu 1360 (1400 byte in IP level) 107 | -rand 0 108 | 109 | | X [ms] | 0 TCP | 1 TCP | 2 TCP | 3 TCP | 4 TCP | 110 | | :- |:-:|:-:|:-:|:-:|:-:| 111 | | 0.25 | 71 | 56 | 46 | 39 | 28 | 112 | | 0.5 | 75 | 60 | 48 | 40 | 30 | 113 | | 1.0 | 68 | 56 | 44 | 38 | 30 | 114 | | 2.0 | 41 | 31 | 29 | 29 | 26 | 115 | 116 | The results indicate that a 2ms microburst interval causes SCReAM to over mark in the DualPi2 AQM. It is therefore recommended to use a smaller microburst interval such as 0.5ms. 117 | The results in general indicated that SCReAM underutilizes the link capacity when is does not need to share the capacity with other flows. This is an expected behavior because of the 50% pacing headroom in SCReAM. Furthermore, SCReAM gets more than its fair share when additional load is applied. 118 | 119 | ### Test 2, different RTTs 120 | The test is run with 4 different values of RTT and up to 4 additional TCP loads 121 | 122 | -microburstinterval 0.5 123 | -mtu 1360 (1400 byte in IP level) 124 | -rand 0 (fixed frame sizes) 125 | 126 | | RTT [ms] | 0 TCP | 1 TCP | 2 TCP | 3 TCP | 4 TCP | 127 | | :- |:-:|:-:|:-:|:-:|:-:| 128 | | 5 | 80 | 55 | 35 | 25 | 22 | 129 | | 10 | 75 | 55 | 44 | 30 | 23 | 130 | | 25 | 75 | 60 | 48 | 40 | 30 | 131 | | 50 | 72 | 50 | 32 | 27 | 22 | 132 | 133 | The results give that SCReAM gives rougly the same results regardless of RTT, within the 5ms - 50ms range. SCReAM also gets more than its fair share when additional load is applied. 134 | 135 | ### Test3, different RTTs, and varying video frame sizes 136 | Like test # 2 but varying video frame sizes 137 | 138 | -microburstinterval 0.5 139 | -mtu 1360 : 1400 byte on IP level 140 | -rand 50 : frame sizes vary +/-1 50% from the nominal (uniform distribution) 141 | 142 | | RTT [ms] | 0 TCP | 1 TCP | 2 TCP | 3 TCP | 4 TCP | 143 | | :- |:-:|:-:|:-:|:-:|:-:| 144 | | 5 | 69 | 45 | 35 | 26 | 18 | 145 | | 10 | 66 | 46 | 40 | 28 | 21 | 146 | | 25 | 64 | 53 | 40 | 32 | 22 | 147 | | 50 | 63 | 52 | 39 | 25 | 18 | 148 | 149 | SCReAM gives a lower bitrate when video frame sizes vary. This is an expected result, given that SCReAM adjusts itself to avoid queue build-up because of larger video frames than expected. SCReAM is also (roughly) more fair against other flows 150 | 151 | | 0 TCP | 1 TCP | 2 TCP | 3 TCP | 4 TCP | 152 | |:-:|:-:|:-:|:-:|:-:| 153 | | 100 | 50 | 33 | 25 | 20 | 154 | 155 | ### Summary 156 | In the given test setup with a 100Mbps DualPi2 AQM it can be concluded that: 157 | 158 | + SCReAM is quite robust under competition from up to 4 competing TCP flows within a 5 to 50ms RTT range. 159 | + SCReAM underutilizes the link capacity when no other competing traffic. This is an expected outcome because of the 50% pacing headroom. 160 | + SCReAM gets more than its fair share of the capacity when frame size is fixed. The unfairness is smaller when frame sizes vary in size. 161 | + Microburst interval = 0.5ms is recommended. 162 | 163 | -------------------------------------------------------------------------------- /test_v_a.m: -------------------------------------------------------------------------------- 1 | function test_v_a(a,Tlim,I,Bmax,Cmax,Dmax) 2 | T = a(:,1); 3 | K = 12; 4 | %Tmax = 100.0; 5 | 6 | 7 | figure(1); 8 | subplot(3,1,1); 9 | ce = a(:,13); 10 | if (I>1) 11 | k = 6; 12 | for n=2:I 13 | ce = ce+a(:,13+k);k=k+6; 14 | end 15 | end 16 | plot(T,a(:,6)/1e3,T,ce/1e3); 17 | set(gca,'FontSize',12);grid on; 18 | set(gca,'XTickLabel',[]); 19 | axis([Tlim(1) Tlim(2) 0 Bmax(1)*1.5]);grid on; 20 | title('Throughput and CE rate [Mbps]'); 21 | 22 | subplot(3,1,2); 23 | plot(T,a(:,2),T,a(:,3)); 24 | %,T,a(:,4)); 25 | set(gca,'FontSize',12);grid on; 26 | set(gca,'XTickLabel',[]); 27 | axis([Tlim(1) Tlim(2) 0 Dmax]);grid on; 28 | title('qdel[s]'); 29 | 30 | subplot(3,1,3); 31 | plot(T,a(:,4),T,a(:,5),T,a(:,7)*20000,'k'); 32 | set(gca,'FontSize',12);grid on; 33 | axis([Tlim(1) Tlim(2) 0 Cmax]);grid on; 34 | title('CWND & in flight [byte]'); 35 | xlabel('T [s]'); 36 | 37 | if I>0 38 | figure(2); 39 | subplot(2,1,1); 40 | plot(T,a(:,8)); 41 | set(gca,'FontSize',12);grid on; 42 | axis([Tlim(1) Tlim(2) 0 0.05]);grid on; 43 | set(gca,'XTickLabel',[]); 44 | title('RTP queue delay [s]'); 45 | subplot(2,1,2); 46 | plot(T,a(:,9)/1000,T,a(:,11)/1000,T,a(:,10)/1000); 47 | set(gca,'FontSize',12);grid on; 48 | axis([Tlim(1) Tlim(2) 0 Bmax(1)]);grid on; 49 | title('Bitrate [Mbps]'); 50 | legend('Target','Transmitted', 'RTP', 'X'); 51 | xlabel('T [s]'); 52 | end 53 | 54 | if I>1 55 | K = 6; 56 | figure(3); 57 | subplot(2,1,1); 58 | plot(T,a(:,8+K)); 59 | set(gca,'FontSize',12);grid on; 60 | axis([Tlim(1) Tlim(2) 0 0.05]);grid on; 61 | set(gca,'XTickLabel',[]); 62 | title('RTP queue delay'); 63 | subplot(2,1,2); 64 | plot(T,a(:,9+K)/1000,T,a(:,11+K)/1000,T,a(:,10+K)/1000); 65 | set(gca,'FontSize',12);grid on; 66 | axis([Tlim(1) Tlim(2) 0 Bmax(2)]);grid on; 67 | title('Bitrate [kbps]'); 68 | legend('Target','Transmitted', 'RTP'); 69 | xlabel('T [s]'); 70 | end 71 | 72 | if I>2 73 | K = 12; 74 | figure(4); 75 | subplot(2,1,1); 76 | plot(T,a(:,8+K)); 77 | set(gca,'FontSize',12);grid on; 78 | axis([Tlim(1) Tlim(2) 0 0.05]);grid on; 79 | set(gca,'XTickLabel',[]); 80 | title('RTP queue delay'); 81 | subplot(2,1,2); 82 | plot(T,a(:,9+K)/1000,T,a(:,11+K)/1000,T,a(:,10+K)/1000); 83 | set(gca,'FontSize',12);grid on; 84 | axis([Tlim(1) Tlim(2) 0 Bmax(3)]);grid on; 85 | title('Bitrate [kbps]'); 86 | legend('Target','Transmitted', 'RTP'); 87 | xlabel('T [s]'); 88 | end 89 | 90 | if I>3 91 | K = 18; 92 | figure(5); 93 | subplot(2,1,1); 94 | plot(T,a(:,8+K)); 95 | set(gca,'FontSize',12);grid on; 96 | axis([Tlim(1) Tlim(2) 0 0.05]);grid on; 97 | set(gca,'XTickLabel',[]); 98 | title('RTP queue delay'); 99 | subplot(2,1,2); 100 | plot(T,a(:,9+K)/1000,T,a(:,11+K)/1000,T,a(:,10+K)/1000); 101 | set(gca,'FontSize',12);grid on; 102 | axis([Tlim(1) Tlim(2) 0 Bmax(3)]);grid on; 103 | title('Bitrate [kbps]'); 104 | legend('Target','Transmitted', 'RTP'); 105 | xlabel('T [s]'); 106 | end 107 | -------------------------------------------------------------------------------- /traces/trace_flat.txt: -------------------------------------------------------------------------------- 1 | 20000 2 | 20000 3 | 20000 4 | 20000 5 | 20000 6 | 20000 7 | 20000 8 | 20000 9 | 20000 10 | 20000 11 | 20000 12 | 20000 13 | 20000 14 | 20000 15 | 20000 16 | 20000 17 | 20000 18 | 20000 19 | 20000 20 | 20000 21 | 20000 22 | 20000 23 | 20000 24 | 20000 25 | 20000 26 | 20000 27 | 20000 28 | 20000 29 | 20000 30 | 20000 31 | 20000 32 | 20000 33 | 20000 34 | 20000 35 | 20000 36 | 20000 37 | 20000 38 | 20000 39 | 20000 40 | 20000 41 | 20000 42 | 20000 43 | 20000 44 | 20000 45 | 20000 46 | 20000 47 | 20000 48 | 20000 49 | 20000 50 | 20000 51 | 20000 52 | 20000 53 | 20000 54 | 20000 55 | 20000 56 | 20000 57 | 20000 58 | 20000 59 | 20000 60 | 20000 61 | 20000 62 | 20000 63 | 20000 64 | 20000 65 | 20000 66 | 20000 67 | 20000 68 | 20000 69 | 20000 70 | 20000 71 | 20000 72 | 20000 73 | 20000 74 | 20000 75 | 20000 76 | 20000 77 | 20000 78 | 20000 79 | 20000 80 | 20000 81 | 20000 82 | 20000 83 | 20000 84 | 20000 85 | 20000 86 | 20000 87 | 20000 88 | 20000 89 | 20000 90 | 20000 91 | 20000 92 | 20000 93 | 20000 94 | 20000 95 | 20000 96 | 20000 97 | 20000 98 | 20000 99 | 20000 100 | 20000 101 | 20000 102 | 20000 103 | 20000 104 | 20000 105 | 20000 106 | 20000 107 | 20000 108 | 20000 109 | 20000 110 | 20000 111 | 20000 112 | 20000 113 | 20000 114 | 20000 115 | 20000 116 | 20000 117 | 20000 118 | 20000 119 | 20000 120 | 20000 121 | 20000 122 | 20000 123 | 20000 124 | 20000 125 | 20000 126 | 20000 127 | 20000 128 | 20000 129 | 20000 130 | 20000 131 | 20000 132 | 20000 133 | 20000 134 | 20000 135 | 20000 136 | 20000 137 | 20000 138 | 20000 139 | 20000 140 | 20000 141 | 20000 142 | 20000 143 | 20000 144 | 20000 145 | 20000 146 | 20000 147 | 20000 148 | 20000 149 | 20000 150 | 20000 151 | 20000 152 | 20000 153 | 20000 154 | 20000 155 | 20000 156 | 20000 157 | 20000 158 | 20000 159 | 20000 160 | 20000 161 | 20000 162 | 20000 163 | 20000 164 | 20000 165 | 20000 166 | 20000 167 | 20000 168 | 20000 169 | 20000 170 | 20000 171 | 20000 172 | 20000 173 | 20000 174 | 20000 175 | 20000 176 | 20000 177 | 20000 178 | 20000 179 | 20000 180 | 20000 181 | 20000 182 | 20000 183 | 20000 184 | 20000 185 | 20000 186 | 20000 187 | 20000 188 | 20000 189 | 20000 190 | 20000 191 | 20000 192 | 20000 193 | 20000 194 | 20000 195 | 20000 196 | 20000 197 | 20000 198 | 20000 199 | 20000 200 | 20000 201 | 20000 202 | 20000 203 | 20000 204 | 20000 205 | 20000 206 | 20000 207 | 20000 208 | 20000 209 | 20000 210 | 20000 211 | 20000 212 | 20000 213 | 20000 214 | 20000 215 | 20000 216 | 20000 217 | 20000 218 | 20000 219 | 20000 220 | 20000 221 | 20000 222 | 20000 223 | 20000 224 | 20000 225 | 20000 226 | 20000 227 | 20000 228 | -------------------------------------------------------------------------------- /version-history.md: -------------------------------------------------------------------------------- 1 | # Older version history 2 | - 2024-10-03 : 3 | - Features that more cautiously increases CWND are removed/refined as these deviated too much from the principle of two marked packets per RTT at steady state. 4 | - 2024-09-27 : 5 | - Limit growth on very small CWND added (optional), to make algorithm more stable at very low bitrates when CWND is just a few MSS 6 | - 2024-07-05 : 7 | - Robustness to large packet reordering improved. Feature is currently only enabled for the BW test application. To enable featire in multicam, add #define EXT_OOO_FB in multicam scream_receiver.cpp. Updated code also fixed an issue where even little reordering triggered packet loss reaction. 8 | - -periodicdropinterval option removed. Periodic rate reduction is instead implemented in ScreamV2Tx.cpp. 9 | - ScreamV1Tx.cpp removed. 10 | - BW test tool, summary output displays %-age of packets marked Not-ECT, ECT(0), ECT(1) and CE. 11 | - 2024-05-31 : 12 | - Congestion window validation modified 13 | - 2024-05-20 : 14 | - -emulatecubic option decoupled for very large CWND. 15 | - -emulatecubic option also made available for gstreamer plugin wrapper 16 | - 2024-05-11 : 17 | - -emulatecubic option modified to be adaptive so that SCReAM will have a reasonable chance to compete against competing Prague flows. -emulatecubic is made optional but is recommended as it stabilizes SCReAM target bitrate and can also reduce delay jitter. 18 | - 2024-05-03 : 19 | - isslowencoder option renamed to -emulatecubic as it behaves similar to TCP Cubic with a more moderate CWND growth close to the last known max value. The -emulatecubic option reduces bitrate variations at steady state but comes with the drawback that SCReAM can have problems to compete with Prague CC 20 | - 2024-04-25 : 21 | - Improved stability at very low bitrates 22 | - Added isslowencoder option for the case that rate increase should be more moderate. This comes with the risk that SCReAM is starved by e.g TCP Prague. 23 | - 2024-04-19 : 24 | - Log item RTP queue delay modified to make it possible to add network queue delay and RTP queue delay to see the actual extra delay for transmitted RTP packets. 25 | - SCReAM BW test tool (SCReAMv2 only): Added openWindow option 26 | - 2024-04-17 : 27 | - ScreamV2Tx : openWindow option did not function properly, fixed. Reaction to sudden drop in throughput improved. 28 | - RtpQueue : code after return statement fixed. 29 | - 2024-04-03 : 30 | - Multicam scream_sender.cpp : multiplicativeIncreaseFactor was erroneously set to 1.0, replaced with a much more correct value 0.05. 31 | - ScreamV2Tx : targetBitrate and RTP queue delay added to extra detailed log (-log option). 32 | - 2024-03-27 : 33 | - Stability issue at very low RTTs fixed. 34 | - 2024-03-22 : 35 | - Added method setIsSlowEncoder to increase robustness when video encoders react slowly to updated target bitrates. 36 | - 2024-03-11 : 37 | - Added support for IPv6 in SCReAM BW test application. 38 | - Added counter for Not-ECT, ECT(0), ECT(1) and CE in summary printout. 39 | - 2024-02-21 : 40 | - Added averaging to transmit and rtp rate logs. 41 | - 2024-01-24 : 42 | - Robustness to sudden jumps in sender or receiver clocks improved. 43 | - 2024-01-19 : 44 | - Stream prioritization refined. 45 | - SCReAM RFC8298 update. First draft available [RFC8298-bis](https://github.com/IngJohEricsson/draft-johansson-ccwg-scream-bis "RFC8298-bin") 46 | - SCReAM V2 is made default for gstreamer application. 47 | - 2024-01-10 : 48 | - SCReAM V2 is made default for BW test and multicam application. 49 | - 2023-12-07 : 50 | - General : Added CE marking percentage to statistics, added function to get statistics items. RTCP format error fixed. 51 | - SCReAM V2 : Delay based CC modified for more stable bitrate. Frame size histogram added to handle large frame size variation better 52 | - 2023-11-12 : SCReAM V2 update. Conditional packet pacing is changed to always pacing when packet pacing is enabled. This removes an odd on/off effect in the packet pacing. Packet pacing implementation is updated to allow for micro burst intervals down to 0.2ms 53 | - 2023-11-03 : SCReAM V2 update. The delay based part of SCReAM V2 is modified such that a virtual L4S alpha is computed when L4S is either disabled or inactive. The virtal L4S alpha is calculated based on the estimated queue delay. The resulting algorithm now abandoned most the LEDBAT style approach that was outlined in RFC8298. Some additional previous voodoo magic is removed in the process. 54 | - 2023-09-20 : SCReAM V2. Version 2 is a major rewrite of the complete algorithm with the goal to make the algorithm more stable, especially when used with L4S. Support for V2 is in the BW test algorithm application and the multicam code. SCReAM V2 is enabled by adding -DV2 in the CMAKE_CXX_FLAGS in CMakeLists.txt
The main changes are: 55 | - The congestion window serves mainly as a hand brake to avoid that excessive amounts of data is injected to the network when link thorughput drops dramatically. The congestion window is otherwise seldom a limiting factor in more normal working conditions 56 | - The packet pacing headroom is made large, as a default, the pacing rate is 50% larger than the nominal target rate. The congestion down-scale is adapted to this to still achieve high link ultilization 57 | - The rate control algorith is greatly simplified, with a minimal amount of voodoo magic that is difficult to explain 58 | - The fast increase mode is replaced with a multiplicative increase that sets in fully a configurable time after congestion 59 | - The final algorithm closely follows the 2 CE marks per RTT rule when used with L4S. 60 | --------------------------------------------------------------------------------