Skip to content

Commit ac780f1

Browse files
committed
Add flag to force monotonous PTS
1 parent 2f203ab commit ac780f1

File tree

3 files changed

+36
-15
lines changed

3 files changed

+36
-15
lines changed

Readme.txt

+9-6
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,17 @@ tsreadex [-z ignored][-s seek][-l limit][-t timeout][-m mode][-x pids][-n prog_n
6464
ARIB文字スーパーをそのままか、補完するか、削除するか。
6565
1のとき、ストリームが存在しなければPMTの項目を補う。
6666

67-
-d flags, range=0 or 1 or 3 or 5 or 7, default=0
67+
-d flags, range=0 or 1 [+2] [+4] [+8], default=0
6868
ARIB字幕/文字スーパーを https://github.com/monyone/aribb24.js が解釈できるID3 timed-metadataに変換する。
6969
変換元のストリームは削除される。
70-
+2(3 or 7)のとき、不明な"private data"ストリームをARIB文字スーパーとして扱う。ffmpegを経由した入力など記述子が正しく転
71-
送されていない入力に対処するもので、普通は使わない。
72-
+4(5 or 7)のとき、変換後のストリームに規格外の5バイトのデータを追加する。これはffmpeg 4.4時点のlibavformat/mpegts.cに
73-
存在するバグを打ち消すためのもので、node-arib-subtitle-timedmetadaterの手法に基づく。出力をffmpegなどに渡す場合にのみ
74-
使用すること。
70+
+2のとき、不明な"private data"ストリームをARIB文字スーパーとして扱う。ffmpegを経由した入力など記述子が正しく転送されて
71+
いない入力に対処するもので、普通は使わない。
72+
+4のとき、変換後のストリームに規格外の5バイトのデータを追加する。これはffmpeg 4.4時点のlibavformat/mpegts.cに存在する
73+
バグを打ち消すためのもので、node-arib-subtitle-timedmetadaterの手法に基づく。出力をffmpegなどに渡す場合にのみ使用する
74+
こと。
75+
+8のとき、変換後のストリームのPTS(Presentation Timestamp)が単調増加となるように調整する。ffmpeg 4.4時点においてPTSを
76+
DTS(Decoding Timestamp)とみなしタイムスタンプが遡るとエラーとなるのを防ぐもの。ARIB字幕/文字スーパーの両方が存在する場
77+
合で、出力をffmpegなどに渡す場合に使用する。
7578

7679
src
7780
入力ファイル名、または"-"で標準入力

id3conv.cpp

+25-9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ CID3Converter::CID3Converter()
55
: m_enabled(false)
66
, m_treatUnknownPrivateDataAsSuperimpose(false)
77
, m_insertInappropriate5BytesIntoPesPayload(false)
8+
, m_forceMonotonousPts(false)
9+
, m_lastID3Pts(-1)
810
, m_firstPmtPid(0)
911
, m_captionPid(0)
1012
, m_superimposePid(0)
@@ -24,6 +26,7 @@ void CID3Converter::SetOption(int flags)
2426
m_enabled = !!(flags & 1);
2527
m_treatUnknownPrivateDataAsSuperimpose = !!(flags & 2);
2628
m_insertInappropriate5BytesIntoPesPayload = !!(flags & 4);
29+
m_forceMonotonousPts = !!(flags & 8);
2730
}
2831

2932
void CID3Converter::AddPacket(const uint8_t *packet)
@@ -242,30 +245,31 @@ void CID3Converter::CheckPrivateDataPes(const std::vector<uint8_t> &pes)
242245
{
243246
const uint8_t PRIVATE_STREAM_1 = 0xbd;
244247
const uint8_t PRIVATE_STREAM_2 = 0xbf;
248+
const int ACCEPTABLE_PTS_DIFF_SEC = 10;
245249

246250
size_t payloadPos = 0;
247-
uint8_t pts[5] = {};
251+
int64_t pts = -1;
248252
if (pes[0] == 0 && pes[1] == 0 && pes[2] == 1) {
249253
int streamID = pes[3];
250254
if (streamID == PRIVATE_STREAM_1 && pes.size() >= 9) {
251255
int ptsDtsFlags = pes[7] >> 6;
252256
payloadPos = 9 + pes[8];
253257
if (ptsDtsFlags >= 2 && pes.size() >= 14) {
254-
std::copy(pes.begin() + 9, pes.begin() + 14, pts);
258+
pts = (pes[13] >> 1) |
259+
(pes[12] << 7) |
260+
((pes[11] & 0xfe) << 14) |
261+
(pes[10] << 22) |
262+
(static_cast<int64_t>(pes[9] & 0x0e) << 29);
255263
}
256264
}
257265
else if (streamID == PRIVATE_STREAM_2) {
258266
payloadPos = 6;
259267
if (m_pcr >= 0) {
260-
pts[0] = static_cast<uint8_t>(m_pcr >> 29) | 0x21; // 3 bits
261-
pts[1] = static_cast<uint8_t>(m_pcr >> 22); // 8 bits
262-
pts[2] = static_cast<uint8_t>(m_pcr >> 14) | 1; // 7 bits
263-
pts[3] = static_cast<uint8_t>(m_pcr >> 7); // 8 bits
264-
pts[4] = static_cast<uint8_t>(m_pcr << 1) | 1; // 7 bits
268+
pts = m_pcr;
265269
}
266270
}
267271
}
268-
if (payloadPos == 0 || payloadPos + 1 >= pes.size() || pts[0] == 0) {
272+
if (payloadPos == 0 || payloadPos + 1 >= pes.size() || pts < 0) {
269273
return;
270274
}
271275
int dataIdentifier = pes[payloadPos];
@@ -275,6 +279,14 @@ void CID3Converter::CheckPrivateDataPes(const std::vector<uint8_t> &pes)
275279
// Not an ARIB Synchronized/Asynchronous PES data
276280
return;
277281
}
282+
if (m_forceMonotonousPts) {
283+
if (m_lastID3Pts >= 0 &&
284+
((0x200000000 + m_lastID3Pts - pts) & 0x1ffffffff) < 90000 * ACCEPTABLE_PTS_DIFF_SEC) {
285+
// Prevent PTS goes back
286+
pts = m_lastID3Pts;
287+
}
288+
m_lastID3Pts = pts;
289+
}
278290

279291
// ID3 Timed Metadata
280292
m_buf.clear();
@@ -286,7 +298,11 @@ void CID3Converter::CheckPrivateDataPes(const std::vector<uint8_t> &pes)
286298
m_buf.push_back(0x80);
287299
m_buf.push_back(0x80);
288300
m_buf.push_back(5);
289-
m_buf.insert(m_buf.end(), pts, pts + 5);
301+
m_buf.push_back(static_cast<uint8_t>(pts >> 29) | 0x21); // 3 bits
302+
m_buf.push_back(static_cast<uint8_t>(pts >> 22)); // 8 bits
303+
m_buf.push_back(static_cast<uint8_t>(pts >> 14) | 1); // 7 bits
304+
m_buf.push_back(static_cast<uint8_t>(pts >> 7)); // 8 bits
305+
m_buf.push_back(static_cast<uint8_t>(pts << 1) | 1); // 7 bits
290306
if (m_insertInappropriate5BytesIntoPesPayload) {
291307
m_buf.insert(m_buf.end(), 5, 0);
292308
}

id3conv.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class CID3Converter
2323
bool m_enabled;
2424
bool m_treatUnknownPrivateDataAsSuperimpose;
2525
bool m_insertInappropriate5BytesIntoPesPayload;
26+
bool m_forceMonotonousPts;
27+
int64_t m_lastID3Pts;
2628
std::vector<uint8_t> m_packets;
2729
PAT m_pat;
2830
int m_firstPmtPid;

0 commit comments

Comments
 (0)