Skip to content

Commit f8f861b

Browse files
committed
Add caption/superimpose mode +4 : insert caption management packet
1 parent fd72ef3 commit f8f861b

File tree

4 files changed

+134
-7
lines changed

4 files changed

+134
-7
lines changed

Readme.txt

+5-2
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,16 @@ tsreadex [-z ignored][-s seek][-l limit][-t timeout][-m mode][-x pids][-n prog_n
6161
3のとき、ストリームが存在しなければ第1音声をコピーする。
6262
+4のとき、モノラルであればステレオにする(AACのみ)。
6363

64-
-c cap, range=0 or 1 or 2, default=0
64+
-c cap, range=0 or 1 or 2 [+4], default=0
6565
ARIB字幕をそのままか、補完するか、削除するか。
6666
1のとき、ストリームが存在しなければPMTの項目を補う。
67+
+4のとき、実際の字幕データが現れない場合に5秒ごとに非表示の適当なデータを挿入する。これはffmpeg 6.0時点で字幕データが
68+
存在しないときにプロセスが終了しなくなる場合があるのを回避するもの。
6769

68-
-u sup, range=0 or 1 or 2, default=0
70+
-u sup, range=0 or 1 or 2 [+4], default=0
6971
ARIB文字スーパーをそのままか、補完するか、削除するか。
7072
1のとき、ストリームが存在しなければPMTの項目を補う。
73+
+4のとき、実際の文字スーパーのデータが現れない場合に5秒ごとに非表示の適当なデータを挿入する("-c"オプションと同様)。
7174

7275
-r trace, default=""
7376
ストリームについての情報をUTF-8文字列で出力するファイル名、または"-"で標準出力。

servicefilter.cpp

+118-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ CServiceFilter::CServiceFilter()
1111
, m_audio1MuxDualMono(false)
1212
, m_captionMode(0)
1313
, m_superimposeMode(0)
14+
, m_captionInsertManagementPacket(false)
15+
, m_superimposeInsertManagementPacket(false)
1416
, m_videoPid(0)
1517
, m_audio1Pid(0)
1618
, m_audio2Pid(0)
@@ -24,11 +26,15 @@ CServiceFilter::CServiceFilter()
2426
, m_pmtCounter(0)
2527
, m_audio1PesCounter(0)
2628
, m_audio2PesCounter(0)
29+
, m_captionPesCounter(0xff)
30+
, m_superimposePesCounter(0xff)
2731
, m_isAudio1DualMono(false)
2832
, m_audio1Pts(-1)
2933
, m_audio2Pts(-1)
3034
, m_audio1PtsPcrDiff(0)
3135
, m_audio2PtsPcrDiff(-1)
36+
, m_captionManagementPcr(-1)
37+
, m_superimposeManagementPcr(-1)
3238
{
3339
static const PAT zeroPat = {};
3440
m_pat = zeroPat;
@@ -48,6 +54,18 @@ void CServiceFilter::SetAudio2Mode(int mode)
4854
m_audio2MuxToStereo = !!(mode & 4);
4955
}
5056

57+
void CServiceFilter::SetCaptionMode(int mode)
58+
{
59+
m_captionMode = mode % 4;
60+
m_captionInsertManagementPacket = !!(mode & 4);
61+
}
62+
63+
void CServiceFilter::SetSuperimposeMode(int mode)
64+
{
65+
m_superimposeMode = mode % 4;
66+
m_superimposeInsertManagementPacket = !!(mode & 4);
67+
}
68+
5169
void CServiceFilter::AddPacket(const uint8_t *packet)
5270
{
5371
if (m_programNumberOrIndex == 0) {
@@ -118,6 +136,39 @@ void CServiceFilter::AddPacket(const uint8_t *packet)
118136
}
119137
AddAudioPesPackets(1, (m_pcr + m_audio2PtsPcrDiff) & 0x1ffffffff, m_audio2Pts, m_audio2PesCounter);
120138
}
139+
140+
static const int INSERT_MANAGEMENT_DETERMINE_ABSENCE_SEC = 15;
141+
static const int INSERT_MANAGEMENT_INTERVAL_SEC = INSERT_MANAGEMENT_DETERMINE_ABSENCE_SEC - 5;
142+
if (m_captionManagementPcr >= 0 &&
143+
m_captionInsertManagementPacket &&
144+
(m_captionPid != 0 || m_captionMode == 1)) {
145+
int64_t pcrDiff = (0x200000000 + m_pcr - m_captionManagementPcr) & 0x1ffffffff;
146+
if (pcrDiff > 90000 * INSERT_MANAGEMENT_DETERMINE_ABSENCE_SEC) {
147+
if (pcrDiff < 90000 * INSERT_MANAGEMENT_DETERMINE_ABSENCE_SEC * 2) {
148+
m_captionPesCounter = (m_captionPesCounter + 1) & 0x0f;
149+
AddCaptionManagementPesPacket(m_pcr, m_captionPesCounter);
150+
}
151+
m_captionManagementPcr = (0x200000000 + m_pcr - 90000 * INSERT_MANAGEMENT_INTERVAL_SEC) & 0x1ffffffff;
152+
}
153+
}
154+
else {
155+
m_captionManagementPcr = m_pcr;
156+
}
157+
if (m_superimposeManagementPcr >= 0 &&
158+
m_superimposeInsertManagementPacket &&
159+
(m_superimposePid != 0 || m_superimposeMode == 1)) {
160+
int64_t pcrDiff = (0x200000000 + m_pcr - m_superimposeManagementPcr) & 0x1ffffffff;
161+
if (pcrDiff > 90000 * INSERT_MANAGEMENT_DETERMINE_ABSENCE_SEC) {
162+
if (pcrDiff < 90000 * INSERT_MANAGEMENT_DETERMINE_ABSENCE_SEC * 2) {
163+
m_superimposePesCounter = (m_superimposePesCounter + 1) & 0x0f;
164+
AddSuperimposeManagementPesPacket(m_superimposePesCounter);
165+
}
166+
m_superimposeManagementPcr = (0x200000000 + m_pcr - 90000 * INSERT_MANAGEMENT_INTERVAL_SEC) & 0x1ffffffff;
167+
}
168+
}
169+
else {
170+
m_superimposeManagementPcr = m_pcr;
171+
}
121172
}
122173
}
123174
}
@@ -195,10 +246,14 @@ void CServiceFilter::AddPacket(const uint8_t *packet)
195246
}
196247
}
197248
else if (pid == m_captionPid) {
198-
ChangePidAndAddPacket(packet, 0x0130);
249+
m_captionManagementPcr = m_pcr;
250+
m_captionPesCounter = m_captionPesCounter > 0x0f ? 0x10 | (counter & 0x0f) : (m_captionPesCounter + 1) & 0x0f;
251+
ChangePidAndAddPacket(packet, 0x0130, m_captionPesCounter & 0x0f);
199252
}
200253
else if (pid == m_superimposePid) {
201-
ChangePidAndAddPacket(packet, 0x0138);
254+
m_superimposeManagementPcr = m_pcr;
255+
m_superimposePesCounter = m_superimposePesCounter > 0x0f ? 0x10 | (counter & 0x0f) : (m_superimposePesCounter + 1) & 0x0f;
256+
ChangePidAndAddPacket(packet, 0x0138, m_superimposePesCounter & 0x0f);
202257
}
203258
else if (pid < 0x0030) {
204259
m_packets.insert(m_packets.end(), packet, packet + 188);
@@ -604,6 +659,67 @@ void CServiceFilter::ChangePidAndAddPacket(const uint8_t *packet, int pid, uint8
604659
m_packets.insert(m_packets.end(), packet + 4, packet + 188);
605660
}
606661

662+
void CServiceFilter::AddCaptionManagementPesPacket(int64_t pts, uint8_t counter)
663+
{
664+
static const uint8_t SYNCHRONOUS_PES_JPN_MANAGEMENT[20] = {
665+
0x80, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x0a,
666+
0x3f, 0x01, 0x1a, 0x6a, 0x70, 0x6e, 0x80, 0x00, 0x00, 0x00,
667+
0xe4, 0x6a
668+
};
669+
m_packets.push_back(0x47);
670+
// PID=0x0130
671+
m_packets.push_back(0x41);
672+
m_packets.push_back(0x30);
673+
m_packets.push_back(0x30 | counter);
674+
m_packets.push_back(188 - 5 - (6 + 28));
675+
m_packets.push_back(0x00);
676+
// stuffing
677+
m_packets.resize(m_packets.size() + 188 - 6 - (6 + 28), 0xff);
678+
// PES
679+
m_packets.push_back(0);
680+
m_packets.push_back(0);
681+
m_packets.push_back(1);
682+
m_packets.push_back(0xbd);
683+
m_packets.push_back(0);
684+
m_packets.push_back(28);
685+
m_packets.push_back(0x80);
686+
// has PTS
687+
m_packets.push_back(0x80);
688+
m_packets.push_back(5);
689+
m_packets.push_back(static_cast<uint8_t>(pts >> 29) | 0x21); // 3 bits
690+
m_packets.push_back(static_cast<uint8_t>(pts >> 22)); // 8 bits
691+
m_packets.push_back(static_cast<uint8_t>(pts >> 14) | 1); // 7 bits
692+
m_packets.push_back(static_cast<uint8_t>(pts >> 7)); // 8 bits
693+
m_packets.push_back(static_cast<uint8_t>(pts << 1) | 1); // 7 bits
694+
m_packets.insert(m_packets.end(), SYNCHRONOUS_PES_JPN_MANAGEMENT, SYNCHRONOUS_PES_JPN_MANAGEMENT + 20);
695+
}
696+
697+
void CServiceFilter::AddSuperimposeManagementPesPacket(uint8_t counter)
698+
{
699+
static const uint8_t ASYNCHRONOUS_PES_JPN_MANAGEMENT[20] = {
700+
0x81, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0a,
701+
0x3f, 0x01, 0x12, 0x6a, 0x70, 0x6e, 0x80, 0x00, 0x00, 0x00,
702+
0xae, 0xa2
703+
};
704+
m_packets.push_back(0x47);
705+
// PID=0x0138
706+
m_packets.push_back(0x41);
707+
m_packets.push_back(0x38);
708+
m_packets.push_back(0x30 | counter);
709+
m_packets.push_back(188 - 5 - (6 + 20));
710+
m_packets.push_back(0x00);
711+
// stuffing
712+
m_packets.resize(m_packets.size() + 188 - 6 - (6 + 20), 0xff);
713+
// PES
714+
m_packets.push_back(0);
715+
m_packets.push_back(0);
716+
m_packets.push_back(1);
717+
m_packets.push_back(0xbf);
718+
m_packets.push_back(0);
719+
m_packets.push_back(20);
720+
m_packets.insert(m_packets.end(), ASYNCHRONOUS_PES_JPN_MANAGEMENT, ASYNCHRONOUS_PES_JPN_MANAGEMENT + 20);
721+
}
722+
607723
void CServiceFilter::AddAudioPesPackets(uint8_t index, int64_t targetPts, int64_t &pts, uint8_t &counter)
608724
{
609725
static const int ACCEPTABLE_PTS_DIFF_SEC = 10;

servicefilter.hpp

+10-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ class CServiceFilter
1212
void SetProgramNumberOrIndex(int n) { m_programNumberOrIndex = n; }
1313
void SetAudio1Mode(int mode);
1414
void SetAudio2Mode(int mode);
15-
void SetCaptionMode(int mode) { m_captionMode = mode; }
16-
void SetSuperimposeMode(int mode) { m_superimposeMode = mode; }
15+
void SetCaptionMode(int mode);
16+
void SetSuperimposeMode(int mode);
1717
void AddPacket(const uint8_t *packet);
1818
const std::vector<uint8_t> &GetPackets() const { return m_packets; }
1919
void ClearPackets() { m_packets.clear(); }
@@ -37,6 +37,8 @@ class CServiceFilter
3737
static int64_t GetAudioPresentationTimeStamp(int unitStart, const uint8_t *payload, int payloadSize);
3838
static bool AccumulatePesPackets(std::vector<uint8_t> &unitPackets, const uint8_t *packet, int unitStart);
3939
static void ConcatenatePayload(std::vector<uint8_t> &dest, const std::vector<uint8_t> &unitPackets, bool &pcrFlag, uint8_t (&pcr)[6]);
40+
void AddCaptionManagementPesPacket(int64_t pts, uint8_t counter);
41+
void AddSuperimposeManagementPesPacket(uint8_t counter);
4042
void AddAudioPesPackets(const std::vector<uint8_t> &pes, int pid, uint8_t &counter, int64_t &ptsPcrDiff, const uint8_t *pcr);
4143
bool TransmuxMonoToStereo(const std::vector<uint8_t> &unitPackets, std::vector<uint8_t> &workspace,
4244
int pid, uint8_t &counter, int64_t &ptsPcrDiff);
@@ -50,6 +52,8 @@ class CServiceFilter
5052
bool m_audio1MuxDualMono;
5153
int m_captionMode;
5254
int m_superimposeMode;
55+
bool m_captionInsertManagementPacket;
56+
bool m_superimposeInsertManagementPacket;
5357
std::vector<uint8_t> m_packets;
5458
PAT m_pat;
5559
PSI m_pmtPsi;
@@ -66,6 +70,8 @@ class CServiceFilter
6670
uint8_t m_pmtCounter;
6771
uint8_t m_audio1PesCounter;
6872
uint8_t m_audio2PesCounter;
73+
uint8_t m_captionPesCounter;
74+
uint8_t m_superimposePesCounter;
6975
bool m_isAudio1DualMono;
7076
std::vector<uint8_t> m_audio1UnitPackets;
7177
std::vector<uint8_t> m_audio2UnitPackets;
@@ -76,6 +82,8 @@ class CServiceFilter
7682
int64_t m_audio2Pts;
7783
int64_t m_audio1PtsPcrDiff;
7884
int64_t m_audio2PtsPcrDiff;
85+
int64_t m_captionManagementPcr;
86+
int64_t m_superimposeManagementPcr;
7987
std::vector<uint8_t> m_buf;
8088
std::vector<uint8_t> m_destLeftBuf;
8189
std::vector<uint8_t> m_destRightBuf;

tsreadex.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ int main(int argc, char **argv)
217217
servicefilter.SetAudio2Mode(mode);
218218
}
219219
else {
220-
invalid = !(0 <= mode && mode <= 2);
220+
invalid = !(0 <= mode && mode <= 6 && mode % 4 <= 2);
221221
if (c == 'c') {
222222
servicefilter.SetCaptionMode(mode);
223223
}

0 commit comments

Comments
 (0)