DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerator
ts_writer.cc
1 // Copyright 2016 Google Inc. 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_writer.h"
8 
9 #include <algorithm>
10 
11 #include "packager/base/logging.h"
12 #include "packager/media/base/audio_stream_info.h"
13 #include "packager/media/base/buffer_writer.h"
14 #include "packager/media/base/stream_info.h"
15 #include "packager/media/base/video_stream_info.h"
16 
17 namespace edash_packager {
18 namespace media {
19 namespace mp2t {
20 
21 namespace {
22 
23 enum Pid : uint8_t {
24  // The pid can be 13 bits long but 8 bits is sufficient for this library.
25  // This is the minimum PID that can be used for PMT.
26  kPmtPid = 0x20,
27  // This is arbitrary number that is not reserved by the spec.
28  kElementaryPid = 0x50,
29 };
30 
31 // Program number is 16 bits but 8 bits is sufficient.
32 const uint8_t kProgramNumber = 0x01;
33 
34 const uint8_t kStreamTypeH264 = 0x1B;
35 const uint8_t kStreamTypeAdtsAac = 0x0F;
36 
37 // For all the pointer fields in the following PAT and PMTs, they are not really
38 // part of PAT or PMT but it's there so that TsPacket can point to a memory
39 // location that starts from pointer field.
40 
41 const uint8_t kProgramAssociationTableId = 0x00;
42 const uint8_t kProgramMapTableId = 0x02;
43 
44 // TODO(rkuroiwa):
45 // Once encryption is added, another PAT must be used for the encrypted portion
46 // e.g. version number set to 1.
47 // But this works for clear lead and for clear segments.
48 // Write PSI generator.
49 const uint8_t kPat[] = {
50  0x00, // pointer field
51  kProgramAssociationTableId,
52  0xB0, // The last 2 '00' assumes that this PAT is not very long.
53  0x0D, // Length of the rest of this array.
54  0x00, 0x00, // Transport stream ID is 0.
55  0xC1, // version number 0, current next indicator 1.
56  0x00, // section number
57  0x00, // last section number
58  // program number -> PMT PID mapping.
59  0x00, 0x01, // program number is 1.
60  0xE0, // first 3 bits is reserved.
61  kPmtPid,
62  // CRC32.
63  0xAB, 0xB9, 0x9E, 0x9D,
64 };
65 
66 // Like PAT, with encryption different PMTs are required.
67 // It might make sense to add a PmtGenerator class.
68 const uint8_t kPmtH264[] = {
69  0x00, // pointer field
70  kProgramMapTableId,
71  0xB0, // assumes length is <= 256 bytes.
72  0x12, // length of the rest of this array.
73  0x00, kProgramNumber,
74  0xC1, // version 0, current next indicator 1.
75  0x00, // section number
76  0x00, // last section number.
77  0xE0, // first 3 bits reserved.
78  kElementaryPid, // PCR PID is the elementary streams PID.
79  0xF0, // first 4 bits reserved.
80  0x00, // No descriptor at this level.
81  kStreamTypeH264, 0xE0, kElementaryPid, // stream_type -> PID.
82  0xF0, 0x00, // Es_info_length is 0.
83  // CRC32.
84  0x56, 0x90, 0xF4, 0xEB,
85 };
86 
87 const uint8_t kPmtAac[] = {
88  0x00, // pointer field
89  0x02, // table id must be 0x02.
90  0xB0, // assumes length is <= 256 bytes.
91  0x12, // length of the rest of this array.
92  0x00, kProgramNumber,
93  0xC1, // version 0, current next indicator 1.
94  0x00, // section number
95  0x00, // last section number.
96  0xE0, // first 3 bits reserved.
97  kElementaryPid, // PCR PID is the elementary streams PID.
98  0xF0, // first 4 bits reserved.
99  0x00, // No descriptor at this level.
100  kStreamTypeAdtsAac, 0xE0, kElementaryPid, // stream_type -> PID.
101  0xF0, 0x00, // Es_info_length is 0.
102  // CRC32.
103  0xC3, 0xF0, 0xC5, 0xA9,
104 };
105 
106 const bool kHasPcr = true;
107 const bool kPayloadUnitStartIndicator = true;
108 
109 const uint8_t kSyncByte = 0x47;
110 const int kPcrFieldsSize = 6;
111 
112 // This is the size of the first few fields in a TS packet, i.e. TS packet size
113 // without adaptation field or the payload.
114 const int kTsPacketHeaderSize = 4;
115 const int kTsPacketSize = 188;
116 const int kTsPacketMaximumPayloadSize =
117  kTsPacketSize - kTsPacketHeaderSize;
118 
119 const size_t kMaxPesPacketLengthValue = 0xFFFF;
120 
121 // Used for adaptation field padding bytes.
122 const uint8_t kPaddingBytes[] = {
123  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
124  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
125  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
126  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
127  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
128  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
129  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
130  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
131  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
132  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
133  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
134  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
135  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
136  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
137  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
138  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
139  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
140  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
141  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
142  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
143  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
144  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
145  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
146  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
147 };
148 static_assert(arraysize(kPaddingBytes) >= kTsPacketMaximumPayloadSize,
149  "Padding array is not big enough.");
150 
151 // |remaining_data_size| is the amount of data that has to be written. This may
152 // be bigger than a TS packet size.
153 // |remaining_data_size| matters if it is short and requires padding.
154 void WriteAdaptationField(bool has_pcr,
155  uint64_t pcr_base,
156  size_t remaining_data_size,
157  BufferWriter* writer) {
158  // Special case where a TS packet requires 1 byte padding.
159  if (!has_pcr && remaining_data_size == kTsPacketMaximumPayloadSize - 1) {
160  writer->AppendInt(static_cast<uint8_t>(0));
161  return;
162  }
163 
164  // The size of the field itself.
165  const int kAdaptationFieldLengthSize = 1;
166 
167  // The size of all leading flags (not including the adaptation_field_length).
168  const int kAdaptationFieldHeaderSize = 1;
169  int adaptation_field_length =
170  kAdaptationFieldHeaderSize + (has_pcr ? kPcrFieldsSize : 0);
171  if (remaining_data_size < kTsPacketMaximumPayloadSize) {
172  const int current_ts_size = kTsPacketHeaderSize + remaining_data_size +
173  adaptation_field_length +
174  kAdaptationFieldLengthSize;
175  if (current_ts_size < kTsPacketSize) {
176  adaptation_field_length += kTsPacketSize - current_ts_size;
177  }
178  }
179 
180  writer->AppendInt(static_cast<uint8_t>(adaptation_field_length));
181  int remaining_bytes = adaptation_field_length;
182  writer->AppendInt(static_cast<uint8_t>(
183  // All flags except PCR_flag are 0.
184  static_cast<uint8_t>(has_pcr) << 4));
185  remaining_bytes -= 1;
186 
187  if (has_pcr) {
188  // program_clock_reference_extension = 0.
189  const uint32_t most_significant_32bits_pcr =
190  static_cast<uint32_t>(pcr_base >> 1);
191  const uint16_t pcr_last_bit_reserved_and_pcr_extension =
192  ((pcr_base & 1) << 15);
193  writer->AppendInt(most_significant_32bits_pcr);
194  writer->AppendInt(pcr_last_bit_reserved_and_pcr_extension);
195  remaining_bytes -= kPcrFieldsSize;
196  }
197  DCHECK_GE(remaining_bytes, 0);
198  if (remaining_bytes == 0)
199  return;
200 
201  DCHECK_GE(static_cast<int>(arraysize(kPaddingBytes)), remaining_bytes);
202  writer->AppendArray(kPaddingBytes, remaining_bytes);
203 }
204 
205 // |payload| can be any payload. Most likely raw PSI tables or PES packet
206 // payload.
207 void WritePayloadToBufferWriter(const uint8_t* payload,
208  size_t payload_size,
209  bool payload_unit_start_indicator,
210  int pid,
211  bool has_pcr,
212  uint64_t pcr_base,
213  ContinuityCounter* continuity_counter,
214  BufferWriter* writer) {
215  size_t payload_bytes_written = 0;
216 
217  do {
218  const bool must_write_adaptation_header = has_pcr;
219  const size_t bytes_left = payload_size - payload_bytes_written;
220  const bool has_adaptation_field = must_write_adaptation_header ||
221  bytes_left < kTsPacketMaximumPayloadSize;
222 
223  writer->AppendInt(kSyncByte);
224  writer->AppendInt(static_cast<uint16_t>(
225  // transport_error_indicator and transport_priority are both '0'.
226  static_cast<int>(payload_unit_start_indicator) << 14 | pid));
227 
228  const uint8_t adaptation_field_control =
229  ((has_adaptation_field ? 1 : 0) << 1) | ((bytes_left != 0) ? 1 : 0);
230  // transport_scrambling_control is '00'.
231  writer->AppendInt(static_cast<uint8_t>(adaptation_field_control << 4 |
232  continuity_counter->GetNext()));
233 
234  if (has_adaptation_field) {
235  const size_t before = writer->Size();
236  WriteAdaptationField(has_pcr, pcr_base, bytes_left, writer);
237  const size_t bytes_for_adaptation_field = writer->Size() - before;
238 
239  const int write_bytes =
240  kTsPacketMaximumPayloadSize - bytes_for_adaptation_field;
241  writer->AppendArray(payload + payload_bytes_written, write_bytes);
242  payload_bytes_written += write_bytes;
243  } else {
244  writer->AppendArray(payload + payload_bytes_written,
245  kTsPacketMaximumPayloadSize);
246  payload_bytes_written += kTsPacketMaximumPayloadSize;
247  }
248 
249  // Once written, not needed for this payload.
250  has_pcr = false;
251  payload_unit_start_indicator = false;
252  } while (payload_bytes_written < payload_size);
253 }
254 
255 void WritePatPmtToBuffer(const uint8_t* data,
256  int data_size,
257  int pid,
258  ContinuityCounter* continuity_counter,
259  BufferWriter* writer) {
260  WritePayloadToBufferWriter(data, data_size, kPayloadUnitStartIndicator, pid,
261  !kHasPcr, 0, continuity_counter, writer);
262 }
263 
264 void WritePatToBuffer(const uint8_t* pat,
265  int pat_size,
266  ContinuityCounter* continuity_counter,
267  BufferWriter* writer) {
268  const int kPatPid = 0;
269  WritePatPmtToBuffer(pat, pat_size, kPatPid, continuity_counter, writer);
270 }
271 
272 void WritePmtToBuffer(const uint8_t* pmt,
273  int pmt_size,
274  ContinuityCounter* continuity_counter,
275  BufferWriter* writer) {
276  WritePatPmtToBuffer(pmt, pmt_size, kPmtPid, continuity_counter, writer);
277 }
278 
279 // The only difference between writing PTS or DTS is the leading bits.
280 void WritePtsOrDts(uint8_t leading_bits,
281  uint64_t pts_or_dts,
282  BufferWriter* writer) {
283  // First byte has 3 MSB of PTS.
284  uint8_t first_byte =
285  leading_bits << 4 | (((pts_or_dts >> 30) & 0x07) << 1) | 1;
286  // Second byte has the next 8 bits of pts.
287  uint8_t second_byte = (pts_or_dts >> 22) & 0xFF;
288  // Third byte has the next 7 bits of pts followed by a marker bit.
289  uint8_t third_byte = (((pts_or_dts >> 15) & 0x7F) << 1) | 1;
290  // Fourth byte has the next 8 bits of pts.
291  uint8_t fourth_byte = ((pts_or_dts >> 7) & 0xFF);
292  // Fifth byte has the last 7 bits of pts followed by a marker bit.
293  uint8_t fifth_byte = ((pts_or_dts & 0x7F) << 1) | 1;
294  writer->AppendInt(first_byte);
295  writer->AppendInt(second_byte);
296  writer->AppendInt(third_byte);
297  writer->AppendInt(fourth_byte);
298  writer->AppendInt(fifth_byte);
299 }
300 
301 bool WritePesToFile(const PesPacket& pes,
302  ContinuityCounter* continuity_counter,
303  File* file) {
304  // The size of the length field.
305  const int kAdaptationFieldLengthSize = 1;
306  // The size of the flags field.
307  const int kAdaptationFieldHeaderSize = 1;
308  const int kPcrFieldSize = 6;
309  const int kTsPacketMaxPayloadWithPcr =
310  kTsPacketMaximumPayloadSize - kAdaptationFieldLengthSize -
311  kAdaptationFieldHeaderSize - kPcrFieldSize;
312  const uint64_t pcr_base = pes.has_dts() ? pes.dts() : pes.pts();
313  const int pid = kElementaryPid;
314 
315  // This writer will hold part of PES packet after PES_packet_length field.
316  BufferWriter pes_header_writer;
317  // The first bit must be '10' for PES with video or audio stream id. The other
318  // flags (bits) don't matter so they are 0.
319  pes_header_writer.AppendInt(static_cast<uint8_t>(0x80));
320  pes_header_writer.AppendInt(
321  static_cast<uint8_t>(static_cast<int>(pes.has_pts()) << 7 |
322  static_cast<int>(pes.has_dts()) << 6
323  // Other fields are all 0.
324  ));
325  uint8_t pes_header_data_length = 0;
326  if (pes.has_pts())
327  pes_header_data_length += 5;
328  if (pes.has_dts())
329  pes_header_data_length += 5;
330  pes_header_writer.AppendInt(pes_header_data_length);
331 
332  if (pes.has_pts() && pes.has_dts()) {
333  WritePtsOrDts(0x03, pes.pts(), &pes_header_writer);
334  WritePtsOrDts(0x01, pes.dts(), &pes_header_writer);
335  } else if (pes.has_pts()) {
336  WritePtsOrDts(0x02, pes.pts(), &pes_header_writer);
337  }
338 
339  // Put the first TS packet's payload into a buffer. This contains the PES
340  // packet's header.
341  BufferWriter first_ts_packet_buffer(kTsPacketSize);
342  first_ts_packet_buffer.AppendNBytes(static_cast<uint64_t>(0x000001), 3);
343  first_ts_packet_buffer.AppendInt(pes.stream_id());
344  const size_t pes_packet_length = pes.data().size() + pes_header_writer.Size();
345  first_ts_packet_buffer.AppendInt(static_cast<uint16_t>(
346  pes_packet_length > kMaxPesPacketLengthValue ? 0 : pes_packet_length));
347  first_ts_packet_buffer.AppendBuffer(pes_header_writer);
348 
349  const int available_payload =
350  kTsPacketMaxPayloadWithPcr - first_ts_packet_buffer.Size();
351  const int bytes_consumed =
352  std::min(static_cast<int>(pes.data().size()), available_payload);
353  first_ts_packet_buffer.AppendArray(pes.data().data(), bytes_consumed);
354 
355  BufferWriter output_writer;
356  WritePayloadToBufferWriter(first_ts_packet_buffer.Buffer(),
357  first_ts_packet_buffer.Size(),
358  kPayloadUnitStartIndicator, pid, kHasPcr, pcr_base,
359  continuity_counter, &output_writer);
360 
361  const size_t remaining_pes_data_size = pes.data().size() - bytes_consumed;
362  if (remaining_pes_data_size > 0) {
363  WritePayloadToBufferWriter(pes.data().data() + bytes_consumed,
364  remaining_pes_data_size,
365  !kPayloadUnitStartIndicator, pid, !kHasPcr, 0,
366  continuity_counter, &output_writer);
367  }
368  return output_writer.WriteToFile(file).ok();
369 }
370 
371 } // namespace
372 
373 ContinuityCounter::ContinuityCounter() {}
374 ContinuityCounter::~ContinuityCounter() {}
375 
377  int ret = counter_;
378  ++counter_;
379  counter_ %= 16;
380  return ret;
381 }
382 
383 TsWriter::TsWriter() {}
384 TsWriter::~TsWriter() {}
385 
386 bool TsWriter::Initialize(const StreamInfo& stream_info) {
387  // This buffer will hold PMT data after section_length field so that this
388  // can be used to get the section_length.
389  time_scale_ = stream_info.time_scale();
390  if (time_scale_ == 0) {
391  LOG(ERROR) << "Timescale is 0.";
392  return false;
393  }
394  const StreamType stream_type = stream_info.stream_type();
395  if (stream_type != StreamType::kStreamVideo &&
396  stream_type != StreamType::kStreamAudio) {
397  LOG(ERROR) << "TsWriter cannot handle stream type " << stream_type
398  << " yet.";
399  return false;
400  }
401 
402  const uint8_t* pmt = nullptr;
403  size_t pmt_size = 0u;
404  if (stream_info.stream_type() == StreamType::kStreamVideo) {
405  const VideoStreamInfo& video_stream_info =
406  static_cast<const VideoStreamInfo&>(stream_info);
407  if (video_stream_info.codec() != VideoCodec::kCodecH264) {
408  LOG(ERROR) << "TsWriter cannot handle video codec "
409  << video_stream_info.codec() << " yet.";
410  return false;
411  }
412  pmt = kPmtH264;
413  pmt_size = arraysize(kPmtH264);
414  } else {
415  DCHECK_EQ(stream_type, StreamType::kStreamAudio);
416  const AudioStreamInfo& audio_stream_info =
417  static_cast<const AudioStreamInfo&>(stream_info);
418  if (audio_stream_info.codec() != AudioCodec::kCodecAAC) {
419  LOG(ERROR) << "TsWriter cannot handle audio codec "
420  << audio_stream_info.codec() << " yet.";
421  return false;
422  }
423  pmt = kPmtAac;
424  pmt_size = arraysize(kPmtAac);
425  }
426  DCHECK(pmt);
427  DCHECK_GT(pmt_size, 0u);
428 
429  // Most likely going to fit in 2 TS packets.
430  BufferWriter psi_writer(kTsPacketSize * 2);
431  WritePatToBuffer(kPat, arraysize(kPat), &pat_continuity_counter_,
432  &psi_writer);
433  WritePmtToBuffer(pmt, pmt_size, &pmt_continuity_counter_, &psi_writer);
434 
435  psi_writer.SwapBuffer(&psi_ts_packets_);
436  return true;
437 }
438 
439 bool TsWriter::NewSegment(const std::string& file_name) {
440  DCHECK(!psi_ts_packets_.empty());
441  if (current_file_) {
442  LOG(ERROR) << "File " << current_file_->file_name() << " still open.";
443  return false;
444  }
445  current_file_.reset(File::Open(file_name.c_str(), "w"));
446  if (!current_file_) {
447  LOG(ERROR) << "Failed to open file " << file_name;
448  return false;
449  }
450 
451  // TODO(kqyang): Add WriteArrayToFile().
452  BufferWriter psi_writer(psi_ts_packets_.size());
453  psi_writer.AppendVector(psi_ts_packets_);
454  if (!psi_writer.WriteToFile(current_file_.get()).ok()) {
455  LOG(ERROR) << "Failed to write PSI to file.";
456  return false;
457  }
458 
459  return true;
460 }
461 
463  return current_file_.release()->Close();
464 }
465 
466 bool TsWriter::AddPesPacket(scoped_ptr<PesPacket> pes_packet) {
467  if (time_scale_ == 0) {
468  LOG(ERROR) << "Timescale is 0.";
469  return false;
470  }
471  DCHECK(current_file_);
472  if (!WritePesToFile(*pes_packet, &elementary_stream_continuity_counter_,
473  current_file_.get())) {
474  LOG(ERROR) << "Failed to write pes to file.";
475  return false;
476  }
477 
478  // No need to keep pes_packet around so not passing it anywhere.
479  return true;
480 }
481 
482 } // namespace mp2t
483 } // namespace media
484 } // namespace edash_packager
Holds audio stream information.
Abstract class holds stream information.
Definition: stream_info.h:26
virtual bool Initialize(const StreamInfo &stream_info)
Definition: ts_writer.cc:386
virtual bool Open()=0
Internal open. Should not be used directly.
virtual bool NewSegment(const std::string &file_name)
Definition: ts_writer.cc:439
virtual bool AddPesPacket(scoped_ptr< PesPacket > pes_packet)
Definition: ts_writer.cc:466
Holds video stream information.