Skip to content

Commit

Permalink
Fixed scrambler issue with short initial input (issue #1070)
Browse files Browse the repository at this point in the history
  • Loading branch information
lelegard committed Oct 23, 2022
1 parent d0c325e commit 965e990
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 20 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.txt
Expand Up @@ -2,7 +2,7 @@ TSDUCK CHANGE LOG AND RELEASE NOTES

-------------------------------------------------------------------------------

VERSION 3.32-2970
VERSION 3.32-2973

[NEW] New commands and plugins:

Expand All @@ -22,6 +22,12 @@ VERSION 3.32-2970
- Options --eit-actual, --eit-other, --eit-pf, --eit-schedule in
"tspacketize", "tstabcomp", plugin "inject".

[BUG] Bug fixes:

* Fixed issue #1070: In the plugin "scrambler", do not fail at startup if
the bitrate is not immediately known. Simply wait for the bitrate to be
known before scheduling crypto-periods and ECM's.

-------------------------------------------------------------------------------

VERSION 3.31-2754
Expand Down
2 changes: 1 addition & 1 deletion src/libtsduck/tsVersion.h
Expand Up @@ -44,4 +44,4 @@
//!
//! TSDuck commit number (automatically updated by Git hooks).
//!
#define TS_COMMIT 2972
#define TS_COMMIT 2973
68 changes: 50 additions & 18 deletions src/tsplugins/tsplugin_scrambler.cpp
Expand Up @@ -45,6 +45,7 @@
#include "tsScramblingDescriptor.h"

#define DEFAULT_ECM_BITRATE 30000
#define DEFAULT_ECM_INTER_PACKET 7000 // When bitrate is unknown, use 10 ECM/s for TS @10Mb/s
#define ASYNC_HANDLER_EXTRA_STACK_SIZE (1024 * 1024)


Expand Down Expand Up @@ -176,6 +177,7 @@ namespace ts {

// ScramblerPlugin state
volatile bool _abort; // Error (service not found, etc)
bool _wait_bitrate; // Waiting for bitrate to start scheduling ECM and CP.
bool _degraded_mode; // In degraded mode (see comments above)
PacketCounter _packet_count; // Complete TS packet counter
PacketCounter _scrambled_count; // Summary of scrambled packets
Expand All @@ -195,6 +197,9 @@ namespace ts {
TSScrambling _scrambling; // Scrambler
CyclingPacketizer _pzer_pmt; // Packetizer for modified PMT

// Initialize ECM and CP scheduling.
void initializeScheduling();

// Return current/next CryptoPeriod for CW or ECM
CryptoPeriod& currentCW() { return _cp[_current_cw]; }
CryptoPeriod& nextCW() { return _cp[(_current_cw + 1) & 0x01]; }
Expand Down Expand Up @@ -246,6 +251,7 @@ ts::ScramblerPlugin::ScramblerPlugin(TSP* tsp_) :
_channel_status(),
_stream_status(),
_abort(false),
_wait_bitrate(false),
_degraded_mode(false),
_packet_count(0),
_scrambled_count(0),
Expand Down Expand Up @@ -414,17 +420,18 @@ bool ts::ScramblerPlugin::start()
_scrambled_count = 0;
_ecm_cc = 0;
_abort = false;
_wait_bitrate = false;
_degraded_mode = false;
_ts_bitrate = 0;
_pkt_insert_ecm = 0;
_pkt_change_cw = 0;
_pkt_change_ecm = 0;
_partial_clear = 0;
_update_pmt = false;
_delay_start = 0;
_current_cw = 0;
_current_ecm = 0;

// As long as the bitrate is unknown, delay changes to infinite.
_pkt_insert_ecm = _pkt_change_cw = _pkt_change_ecm = std::numeric_limits<PacketCounter>::max();

// Initialize the scrambling engine.
if (!_scrambling.start()) {
return false;
Expand Down Expand Up @@ -500,20 +507,13 @@ bool ts::ScramblerPlugin::stop()


//----------------------------------------------------------------------------
// This method processes the PMT of the service.
// This method processes the PMT of the service.
//----------------------------------------------------------------------------

void ts::ScramblerPlugin::handlePMT(const PMT& table, PID)
{
assert(_use_service);

// We need to know the bitrate in order to schedule crypto-periods or ECM insertion.
if (_ts_bitrate == 0 && (_need_cp || _need_ecm)) {
tsp->error(u"unknown bitrate, cannot schedule crypto-periods");
_abort = true;
return;
}

// Need a modifiable version of the PMT.
PMT pmt(table);

Expand Down Expand Up @@ -585,21 +585,47 @@ void ts::ScramblerPlugin::handlePMT(const PMT& table, PID)
_pzer_pmt.addTable(duck, pmt);
}

// We need to know the bitrate in order to schedule crypto-periods or ECM insertion.
if (_need_cp || _need_ecm) {
if (_ts_bitrate == 0) {
_wait_bitrate = true;
tsp->warning(u"unknown bitrate, scheduling of crypto-periods is delayed");
}
else {
initializeScheduling();
}
}
}


//----------------------------------------------------------------------------
// Initialize ECM and CP scheduling.
//----------------------------------------------------------------------------

void ts::ScramblerPlugin::initializeScheduling()
{
assert(_ts_bitrate != 0);

// Next crypto-period.
if (_need_cp) {
_pkt_change_cw = _packet_count + PacketDistance(_ts_bitrate, _ecmg_args.cp_duration);
}

// Initialize ECM insertion.
if (_need_ecm) {

// Insert current ECM packets as soon as possible.
_pkt_insert_ecm = _packet_count;

// Next ECM may start before or after next crypto-period
_pkt_change_ecm = _delay_start > 0 ?
_pkt_change_cw + PacketDistance(_ts_bitrate, _delay_start) :
_pkt_change_cw - PacketDistance(_ts_bitrate, _delay_start);
_pkt_change_cw + PacketDistance(_ts_bitrate, _delay_start) :
_pkt_change_cw - PacketDistance(_ts_bitrate, _delay_start);
}

// No longer wait for bitrate.
if (_wait_bitrate) {
_wait_bitrate = false;
tsp->info(u"bitrate now known, %'d b/s, starting scheduling crypto-periods", {_ts_bitrate});
}
}

Expand Down Expand Up @@ -641,6 +667,7 @@ bool ts::ScramblerPlugin::tryExitDegradedMode()
return true;
}
assert(_need_ecm);
assert(_ts_bitrate != 0);

// We are in degraded mode. If next ECM not yet ready, stay degraded
if (!nextECM().ecmReady()) {
Expand Down Expand Up @@ -684,7 +711,7 @@ bool ts::ScramblerPlugin::changeCW()
_current_cw = (_current_cw + 1) & 0x01;

// Determine new transition point.
if (_need_cp) {
if (_need_cp && _ts_bitrate != 0) {
_pkt_change_cw = _packet_count + PacketDistance(_ts_bitrate, _ecmg_args.cp_duration);
}

Expand All @@ -704,7 +731,7 @@ bool ts::ScramblerPlugin::changeCW()
}

// Determine new transition point.
if (_need_cp) {
if (_need_cp && _ts_bitrate != 0) {
_pkt_change_cw = _packet_count + PacketDistance(_ts_bitrate, _ecmg_args.cp_duration);
}

Expand All @@ -719,7 +746,7 @@ bool ts::ScramblerPlugin::changeCW()
void ts::ScramblerPlugin::changeECM()
{
// Allowed to change CW only if not in degraded mode
if (_need_ecm && !inDegradedMode()) {
if (_need_ecm && _ts_bitrate != 0 && !inDegradedMode()) {

// Point to next crypto-period
_current_ecm = (_current_ecm + 1) & 0x01;
Expand Down Expand Up @@ -752,6 +779,9 @@ ts::ProcessorPlugin::Status ts::ScramblerPlugin::processPacket(TSPacket& pkt, TS
const BitRate br = tsp->bitrate();
if (br != 0) {
_ts_bitrate = br;
if (_wait_bitrate) {
initializeScheduling();
}
}

// Filter interesting sections to discover the service.
Expand Down Expand Up @@ -798,7 +828,7 @@ ts::ProcessorPlugin::Status ts::ScramblerPlugin::processPacket(TSPacket& pkt, TS

// Compute next insertion point (approximate)
assert(_ecm_bitrate != 0);
_pkt_insert_ecm += BitRate(_ts_bitrate / _ecm_bitrate).toInt();
_pkt_insert_ecm += _ts_bitrate == 0 ? DEFAULT_ECM_INTER_PACKET : BitRate(_ts_bitrate / _ecm_bitrate).toInt();

// Try to exit from degraded mode, if we were in.
// Note that return false means unrecoverable error here.
Expand Down Expand Up @@ -908,6 +938,8 @@ void ts::ScramblerPlugin::CryptoPeriod::initNext(const CryptoPeriod& previous)

bool ts::ScramblerPlugin::CryptoPeriod::initScramblerKey() const
{
_plugin->debug(u"starting crypto-period %'d at packet %'d", {_cp_number, _plugin->_packet_count});

// Change the parity of the scrambled packets.
// Set our random current control word if no fixed CW.
return _plugin->_scrambling.setEncryptParity(_cp_number) &&
Expand Down

0 comments on commit 965e990

Please sign in to comment.