Skip to content

Commit

Permalink
Update : Addition of bitrate calculation and log display using PCR.
Browse files Browse the repository at this point in the history
  • Loading branch information
ysan committed Dec 21, 2023
1 parent 908fcb5 commit d0a1a3a
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 33 deletions.
70 changes: 70 additions & 0 deletions src/parser/TsAribCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,76 @@ typedef struct _ts_header {

} TS_HEADER;

struct adaptation_field_header_t {
void parse (const uint8_t* p_src) {
if (!p_src) {
return;
}
discontinuity_indicator = (*(p_src) >> 7) & 0x1;
random_access_indicator = (*(p_src) >> 6) & 0x1;
elemetary_stream_priority_indicator = (*(p_src) >> 5) & 0x1;
PCR_flag = (*(p_src) >> 4) & 0x1;
OPCR_flag = (*(p_src) >> 3) & 0x1;
splicing_point_flag = (*(p_src) >> 2) & 0x1;
transport_private_data_flag = (*(p_src) >> 1) & 0x1;
adaptation_field_extension_flag = *(p_src) & 0x1;
}

void clear (void) {
discontinuity_indicator = 0;
random_access_indicator = 0;
elemetary_stream_priority_indicator = 0;
PCR_flag = 0;
OPCR_flag = 0;
splicing_point_flag = 0;
transport_private_data_flag = 0;
adaptation_field_extension_flag = 0;
}

void dump (void) const {
_UTL_LOG_I (
"af-hdr: di:[%d] rai:[%d] espi:[%d] PCR:[%d] OPCR:[%d] spf:[%d] tpdf:[%d] afef:[%d]\n",
discontinuity_indicator,
random_access_indicator,
elemetary_stream_priority_indicator,
PCR_flag,
OPCR_flag,
splicing_point_flag,
transport_private_data_flag,
adaptation_field_extension_flag
);
}

uint8_t discontinuity_indicator;
uint8_t random_access_indicator;
uint8_t elemetary_stream_priority_indicator;
uint8_t PCR_flag;
uint8_t OPCR_flag;
uint8_t splicing_point_flag;
uint8_t transport_private_data_flag;
uint8_t adaptation_field_extension_flag;
};

struct pcr_t {
explicit pcr_t (const uint8_t* p_src) {
parse(p_src);
}
virtual ~pcr_t (void) = default;

void parse (const uint8_t* p_src) {
if (!p_src) {
return;
}
uint32_t dw = *(p_src+0) << 24 | *(p_src+1) << 16 | *(p_src+2) << 8 | *(p_src+3);
uint16_t w = *(p_src+4) << 8 | *(p_src+5);
uint64_t base = (uint64_t)dw << 1 | ((w >> 15) & 0x1);
uint64_t extension = (uint64_t)w & 0x1ff;
pcr = base * 300 + extension;
}

uint64_t pcr;
};

typedef struct _section_header {

void dump (void) const {
Expand Down
87 changes: 59 additions & 28 deletions src/parser/TsParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,57 @@
#include <unistd.h>
#include <errno.h>

#include "TsAribCommon.h"
#include "TsParser.h"
#include "Utils.h"


CTsParser::CTsParser (void)
:mp_top (NULL)
,mp_current (NULL)
,mp_bottom (NULL)
,m_buff_size (0)
,m_parse_remain_len (0)
,mp_listener (NULL)
: mp_top (nullptr)
, mp_current (nullptr)
, mp_bottom (nullptr)
, m_parse_remain_len (0)
, mp_listener (nullptr)
{
std::unique_ptr<uint8_t[]> up (new uint8_t[INNER_BUFF_SIZE]);
m_inner_buff.swap(up);
reset();

m_bitrate.set_interval(60*2, [](double bitrate, uint64_t bytes, uint64_t clocks){
_UTL_LOG_I("bitrate -- %.3f bps (%llu bytes * 8 / (%llu clocks * 27MHz))", bitrate, bytes, clocks);
});
}

CTsParser::CTsParser (IParserListener *p_listener)
:mp_top (NULL)
,mp_current (NULL)
,mp_bottom (NULL)
,m_buff_size (0)
,m_parse_remain_len (0)
,mp_listener (NULL)
: mp_top (nullptr)
, mp_current (nullptr)
, mp_bottom (nullptr)
, m_parse_remain_len (0)
, mp_listener (nullptr)
{
if (p_listener) {
mp_listener = p_listener;
}

std::unique_ptr<uint8_t[]> up (new uint8_t[INNER_BUFF_SIZE]);
m_inner_buff.swap(up);
reset();

m_bitrate.set_interval(60*2, [](double bitrate, uint64_t bytes, uint64_t clocks){
_UTL_LOG_I("bitrate -- %.3f bps (%llu bytes * 8 / (%llu clocks * 27MHz))", bitrate, bytes, clocks);
});
}

CTsParser::~CTsParser (void)
void CTsParser::reset (void)
{
std::unique_ptr<uint8_t[]> up (new uint8_t[INNER_BUFF_SIZE]);
m_inner_buff = std::move(up);

mp_top = nullptr;
mp_current = nullptr;
mp_bottom = nullptr;
m_parse_remain_len = 0;

m_bitrate.reset();
}

void CTsParser::run (uint8_t *p_buff, size_t size)
void CTsParser::put (uint8_t *p_buff, size_t size)
{
if ((!p_buff) || (size == 0)) {
return ;
Expand Down Expand Up @@ -131,14 +145,14 @@ int CTsParser::get_unit_size (void) const
uint8_t * CTsParser::get_sync_top_addr (uint8_t *p_start, uint8_t *p_end, size_t unit_size) const
{
if ((!p_start) || (!p_end) || (unit_size == 0)) {
return NULL;
return nullptr;
}

if ((uint32_t)(p_end - p_start) >= (unit_size * 8)) {
// unit_size 8コ分のデータがあること
p_end -= unit_size * 8;
} else {
return NULL;
return nullptr;
}

int i = 0;
Expand All @@ -157,7 +171,7 @@ uint8_t * CTsParser::get_sync_top_addr (uint8_t *p_start, uint8_t *p_end, size_t
++ p_start ;
}

return NULL;
return nullptr;
}

int CTsParser::check_unit_size (void)
Expand Down Expand Up @@ -195,7 +209,8 @@ bool CTsParser::parse (void)
int unit_size = 0;
int err_cnt = 0;
TS_HEADER ts_header = {0};
uint8_t *p_payload = NULL;
adaptation_field_header_t af_header = {0};
uint8_t *p_payload = nullptr;
uint8_t *p_cur = mp_current;
uint8_t *p_btm = mp_bottom;
size_t payload_size = 0;
Expand All @@ -222,17 +237,31 @@ bool CTsParser::parse (void)
}

ts_header.parse (p_cur);
af_header.clear();

p_payload = p_cur + TS_HEADER_LEN;
m_bitrate.update_size(unit_size);

// adaptation_field_control 2bit
// 00 ISO/IECによる将来の使用のために予約されている。
// 01 アダプテーションフィールドなし、ペイロードのみ
// 10 アダプテーションフィールドのみ、ペイロードなし
// 11 アダプテーションフィールドの次にペイロード
if ((ts_header.adaptation_field_control & 0x02) == 0x02) {
if ((ts_header.adaptation_field_control & 0x2) == 0x2) {
// アダプテーションフィールド付き
p_payload += *p_payload + 1; // lengthとそれ自身の1byte分進める
size_t adaptation_field_length = *(p_cur + TS_HEADER_LEN);
p_payload += adaptation_field_length + 1; // lengthとそれ自身の1byte分進める

if (adaptation_field_length > 0) {
af_header.parse(p_cur + TS_HEADER_LEN + 1);
if (af_header.PCR_flag) {
pcr_t pcr(p_cur + TS_HEADER_LEN + 2);
m_bitrate.update_pcr(pcr.pcr);
}
}

} else {
// アダプテーションフィールドなし
p_payload = p_cur + TS_HEADER_LEN;
}

// TTS(Timestamped TS)(total192bytes) や
Expand All @@ -241,9 +270,11 @@ bool CTsParser::parse (void)
// payload_size = TS_PACKET_LEN - (p_payload - p_cur);
payload_size = TS_PACKET_LEN - TS_HEADER_LEN;


if (mp_listener) {
mp_listener->on_ts_packet_available (&ts_header, p_payload, payload_size);
if (ts_header.adaptation_field_control != 0x2) {
// ペイロード有る時のみ
if (mp_listener) {
mp_listener->on_ts_packet_available (&ts_header, p_payload, payload_size);
}
}

p_cur += unit_size;
Expand Down
83 changes: 79 additions & 4 deletions src/parser/TsParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
#include <errno.h>

#include <memory>
#include <chrono>
#include <functional>

#include "Defs.h"

#include "TsAribCommon.h"
#include "Utils.h"


class CTsParser
Expand All @@ -23,6 +26,76 @@ class CTsParser
virtual bool on_ts_packet_available (TS_HEADER *p_header, uint8_t *p_payload, size_t payload_size) = 0;
};

class CBitRate {
public:
static constexpr uint64_t pcr_max = 0x1ffffffffULL * 300 + 0x1ff; // pcr 42bit counter (33bit * 300 + 9bit)
static constexpr double pcr_clock_freq = 27000000; // 27MHz

CBitRate (void)
: m_interval_sec(0)
, m_interval_cb(nullptr)
, m_total_size(0)
, m_start_pcr(0)
, m_end_pcr(0)
{
}
virtual ~CBitRate (void) = default;

void set_interval (int interval_sec, std::function<void(double bitrate, uint64_t bytes, uint64_t clocks)> interval_cb) {
m_interval_sec = interval_sec;
m_interval_cb = interval_cb;
}

void reset (void) {
m_total_size = 0;
m_start_pcr = 0;
m_end_pcr = 0;
m_start_tp = std::chrono::steady_clock::now();
}

void update_size (size_t size) {
m_total_size += size;
}

void update_pcr (uint64_t pcr) {
if (pcr == 0) {
return;
}

if (m_start_pcr == 0) {
m_start_pcr = pcr;
m_end_pcr = pcr;
} else {
m_end_pcr = pcr;
}

auto now = std::chrono::steady_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::seconds>(now - m_start_tp).count();
if (diff > m_interval_sec) {
uint64_t pcr_d = 0;
if (m_end_pcr >= m_start_pcr) {
pcr_d = m_end_pcr - m_start_pcr;
} else {
pcr_d = (m_end_pcr + pcr_max) - m_start_pcr;
}
double bitrate = (double)m_total_size * 8 / (pcr_d / pcr_clock_freq);
if (m_interval_cb) {
m_interval_cb (bitrate, m_total_size, pcr_d);
}

reset();
}
}

private:
int m_interval_sec;
std::function<void(double bitrate, uint64_t bytes, uint64_t clocks)> m_interval_cb;
uint64_t m_total_size;
uint64_t m_start_pcr;
uint64_t m_end_pcr;
std::chrono::steady_clock::time_point m_start_tp;
};

public:
static constexpr uint32_t INNER_BUFF_SIZE = 65535*5;

Expand All @@ -33,12 +106,13 @@ class CTsParser

CTsParser (void);
explicit CTsParser (IParserListener *p_listener);
virtual ~CTsParser (void);
virtual ~CTsParser (void) = default;

void run (uint8_t *buff, size_t size);
void reset (void);

void put (uint8_t *buff, size_t size);

private:
bool allocate_to_inner_buffer (uint8_t *p_buff, size_t size);
buff_state copy_to_inner_buffer (uint8_t *p_buff, size_t size);
int get_unit_size (void) const;
uint8_t *get_sync_top_addr (uint8_t *p_top, uint8_t *p_bottom, size_t unit_size) const;
Expand All @@ -49,12 +123,13 @@ class CTsParser
uint8_t *mp_top ;
uint8_t *mp_current ;
uint8_t *mp_bottom ;
size_t m_buff_size ;
int m_parse_remain_len;

IParserListener *mp_listener;

std::unique_ptr<uint8_t[]> m_inner_buff;

CBitRate m_bitrate;
};

#endif
4 changes: 3 additions & 1 deletion src/psisi_manager/PsisiManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2372,6 +2372,8 @@ bool CPsisiManager::on_pre_ts_receive (void)
opt |= REQUEST_OPTION__WITHOUT_REPLY;
get_external_if()->set_request_option (opt);

m_parser.reset();

return true;
}

Expand All @@ -2393,7 +2395,7 @@ bool CPsisiManager::on_ts_received (void *p_ts_data, int length)
{

// ts parser processing
m_parser.run ((uint8_t*)p_ts_data, length);
m_parser.put ((uint8_t*)p_ts_data, length);

return true;
}
Expand Down

0 comments on commit d0a1a3a

Please sign in to comment.