Shaka Packager SDK
Loading...
Searching...
No Matches
ts_packet_writer_util.cc
1// Copyright 2016 Google LLC. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file or at
5// https://developers.google.com/open-source/licenses/bsd
6
7#include <packager/media/formats/mp2t/ts_packet_writer_util.h>
8
9#include <absl/log/check.h>
10#include <absl/log/log.h>
11
12#include <packager/media/base/buffer_writer.h>
13#include <packager/media/formats/mp2t/continuity_counter.h>
14
15namespace shaka {
16namespace media {
17namespace mp2t {
18
19namespace {
20
21const int kPcrFieldsSize = 6;
22const uint8_t kSyncByte = 0x47;
23
24// This is the size of the first few fields in a TS packet, i.e. TS packet size
25// without adaptation field or the payload.
26const int kTsPacketHeaderSize = 4;
27const int kTsPacketSize = 188;
28const int kTsPacketMaximumPayloadSize =
29 kTsPacketSize - kTsPacketHeaderSize;
30
31// Used for adaptation field padding bytes.
32const uint8_t kPaddingBytes[] = {
33 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
34 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
35 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
36 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
37 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
38 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
39 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
40 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
41 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
42 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
43 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
44 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
45 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
46 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
47 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
48 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
49 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
50 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
51 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
52 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
53 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
54 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
55 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
56 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
57};
58static_assert(std::size(kPaddingBytes) >= kTsPacketMaximumPayloadSize,
59 "Padding array is not big enough.");
60
61// |remaining_data_size| is the amount of data that has to be written. This may
62// be bigger than a TS packet size.
63// |remaining_data_size| matters if it is short and requires padding.
64void WriteAdaptationField(bool has_pcr,
65 uint64_t pcr_base,
66 size_t remaining_data_size,
67 BufferWriter* writer) {
68 // Special case where a TS packet requires 1 byte padding.
69 if (!has_pcr && remaining_data_size == kTsPacketMaximumPayloadSize - 1) {
70 writer->AppendInt(static_cast<uint8_t>(0));
71 return;
72 }
73
74 // The size of the field itself.
75 const int kAdaptationFieldLengthSize = 1;
76
77 // The size of all leading flags (not including the adaptation_field_length).
78 const int kAdaptationFieldHeaderSize = 1;
79 size_t adaptation_field_length =
80 kAdaptationFieldHeaderSize + (has_pcr ? kPcrFieldsSize : 0);
81 if (remaining_data_size < kTsPacketMaximumPayloadSize) {
82 const size_t current_ts_size = kTsPacketHeaderSize + remaining_data_size +
83 adaptation_field_length +
84 kAdaptationFieldLengthSize;
85 if (current_ts_size < kTsPacketSize) {
86 adaptation_field_length += kTsPacketSize - current_ts_size;
87 }
88 }
89
90 writer->AppendInt(static_cast<uint8_t>(adaptation_field_length));
91 int remaining_bytes = static_cast<int>(adaptation_field_length);
92 writer->AppendInt(static_cast<uint8_t>(
93 // All flags except PCR_flag are 0.
94 static_cast<uint8_t>(has_pcr) << 4));
95 remaining_bytes -= 1;
96
97 if (has_pcr) {
98 // program_clock_reference_extension = 0.
99 const uint32_t most_significant_32bits_pcr =
100 static_cast<uint32_t>(pcr_base >> 1);
101 const uint16_t pcr_last_bit_reserved_and_pcr_extension =
102 ((pcr_base & 1) << 15) | 0x7e00; // Set the 6 reserved bits to '1'
103 writer->AppendInt(most_significant_32bits_pcr);
104 writer->AppendInt(pcr_last_bit_reserved_and_pcr_extension);
105 remaining_bytes -= kPcrFieldsSize;
106 }
107 DCHECK_GE(remaining_bytes, 0);
108 if (remaining_bytes == 0)
109 return;
110
111 DCHECK_GE(static_cast<int>(std::size(kPaddingBytes)), remaining_bytes);
112 writer->AppendArray(kPaddingBytes, remaining_bytes);
113}
114
115} // namespace
116
117void WritePayloadToBufferWriter(const uint8_t* payload,
118 size_t payload_size,
119 bool payload_unit_start_indicator,
120 int pid,
121 bool has_pcr,
122 uint64_t pcr_base,
123 ContinuityCounter* continuity_counter,
124 BufferWriter* writer) {
125 size_t payload_bytes_written = 0;
126
127 do {
128 const bool must_write_adaptation_header = has_pcr;
129 const size_t bytes_left = payload_size - payload_bytes_written;
130 const bool has_adaptation_field = must_write_adaptation_header ||
131 bytes_left < kTsPacketMaximumPayloadSize;
132
133 writer->AppendInt(kSyncByte);
134 writer->AppendInt(static_cast<uint16_t>(
135 // transport_error_indicator and transport_priority are both '0'.
136 static_cast<int>(payload_unit_start_indicator) << 14 | pid));
137
138 const uint8_t adaptation_field_control =
139 ((has_adaptation_field ? 1 : 0) << 1) | ((bytes_left != 0) ? 1 : 0);
140 // transport_scrambling_control is '00'.
141 writer->AppendInt(static_cast<uint8_t>(adaptation_field_control << 4 |
142 continuity_counter->GetNext()));
143
144 if (has_adaptation_field) {
145 const size_t before = writer->Size();
146 WriteAdaptationField(has_pcr, pcr_base, bytes_left, writer);
147 const size_t bytes_for_adaptation_field = writer->Size() - before;
148
149 const size_t write_bytes =
150 kTsPacketMaximumPayloadSize - bytes_for_adaptation_field;
151 writer->AppendArray(payload + payload_bytes_written, write_bytes);
152 payload_bytes_written += write_bytes;
153 } else {
154 writer->AppendArray(payload + payload_bytes_written,
155 kTsPacketMaximumPayloadSize);
156 payload_bytes_written += kTsPacketMaximumPayloadSize;
157 }
158
159 // Once written, not needed for this payload.
160 has_pcr = false;
161 payload_unit_start_indicator = false;
162 } while (payload_bytes_written < payload_size);
163}
164
165} // namespace mp2t
166} // namespace media
167} // namespace shaka
All the methods that are virtual are virtual for mocking.