Shaka Packager SDK
pes_packet_generator.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/pes_packet_generator.h>
8 
9 #include <algorithm>
10 #include <cstring>
11 #include <memory>
12 
13 #include <absl/log/check.h>
14 
15 #include <packager/macros/logging.h>
16 #include <packager/media/base/audio_stream_info.h>
17 #include <packager/media/base/buffer_writer.h>
18 #include <packager/media/base/media_sample.h>
19 #include <packager/media/base/video_stream_info.h>
20 #include <packager/media/codecs/aac_audio_specific_config.h>
21 #include <packager/media/codecs/nal_unit_to_byte_stream_converter.h>
22 #include <packager/media/codecs/nalu_reader.h>
23 #include <packager/media/formats/mp2t/pes_packet.h>
24 
25 namespace shaka {
26 namespace media {
27 namespace mp2t {
28 
29 namespace {
30 const uint8_t kVideoStreamId = 0xE0;
31 const uint8_t kAacAudioStreamId = 0xC0;
32 const uint8_t kAc3AudioStreamId = 0xBD; // AC3 uses private stream 1 id.
33 const double kTsTimescale = 90000.0;
34 } // namespace
35 
37  int32_t transport_stream_timestamp_offset)
38  : transport_stream_timestamp_offset_(transport_stream_timestamp_offset) {}
39 
40 PesPacketGenerator::~PesPacketGenerator() {}
41 
42 bool PesPacketGenerator::Initialize(const StreamInfo& stream_info) {
43  pes_packets_.clear();
44  stream_type_ = stream_info.stream_type();
45 
46  if (stream_type_ == kStreamVideo) {
47  const VideoStreamInfo& video_stream_info =
48  static_cast<const VideoStreamInfo&>(stream_info);
49  if (video_stream_info.codec() != Codec::kCodecH264) {
50  NOTIMPLEMENTED() << "Video codec " << video_stream_info.codec()
51  << " is not supported.";
52  return false;
53  }
54  timescale_scale_ = kTsTimescale / video_stream_info.time_scale();
55  converter_.reset(new NalUnitToByteStreamConverter());
56  return converter_->Initialize(video_stream_info.codec_config().data(),
57  video_stream_info.codec_config().size());
58  }
59  if (stream_type_ == kStreamAudio) {
60  const AudioStreamInfo& audio_stream_info =
61  static_cast<const AudioStreamInfo&>(stream_info);
62  timescale_scale_ = kTsTimescale / audio_stream_info.time_scale();
63  if (audio_stream_info.codec() == Codec::kCodecAAC) {
64  audio_stream_id_ = kAacAudioStreamId;
65  adts_converter_.reset(new AACAudioSpecificConfig());
66  return adts_converter_->Parse(audio_stream_info.codec_config());
67  }
68  if (audio_stream_info.codec() == Codec::kCodecAC3 ||
69  audio_stream_info.codec() == Codec::kCodecEAC3 ||
70  audio_stream_info.codec() == Codec::kCodecMP3) {
71  audio_stream_id_ = kAc3AudioStreamId;
72  // No converter needed for AC3, E-AC3 and MP3.
73  return true;
74  }
75  NOTIMPLEMENTED() << "Audio codec " << audio_stream_info.codec()
76  << " is not supported yet.";
77  return false;
78  }
79 
80  NOTIMPLEMENTED() << "Stream type: " << stream_type_ << " not implemented.";
81  return false;
82 }
83 
85  if (!current_processing_pes_)
86  current_processing_pes_.reset(new PesPacket());
87 
88  const int64_t pts =
89  sample.pts() * timescale_scale_ + transport_stream_timestamp_offset_;
90  const int64_t dts =
91  sample.dts() * timescale_scale_ + transport_stream_timestamp_offset_;
92 
93  if (pts < 0 || dts < 0) {
94  LOG(ERROR) << "Seeing negative timestamp (" << pts << "," << dts << ")"
95  << " after applying offset "
96  << transport_stream_timestamp_offset_
97  << ". Please check if it is expected. Adjust "
98  "--transport_stream_timestamp_offset_ms if needed.";
99  return false;
100  }
101 
102  current_processing_pes_->set_is_key_frame(sample.is_key_frame());
103  current_processing_pes_->set_pts(pts);
104  current_processing_pes_->set_dts(dts);
105  if (stream_type_ == kStreamVideo) {
106  DCHECK(converter_);
107  std::vector<SubsampleEntry> subsamples;
108  if (sample.decrypt_config())
109  subsamples = sample.decrypt_config()->subsamples();
110  const bool kEscapeEncryptedNalu = true;
111  std::vector<uint8_t> byte_stream;
112  if (!converter_->ConvertUnitToByteStreamWithSubsamples(
113  sample.data(), sample.data_size(), sample.is_key_frame(),
114  kEscapeEncryptedNalu, &byte_stream, &subsamples)) {
115  LOG(ERROR) << "Failed to convert sample to byte stream.";
116  return false;
117  }
118 
119  current_processing_pes_->mutable_data()->swap(byte_stream);
120  current_processing_pes_->set_stream_id(kVideoStreamId);
121  pes_packets_.push_back(std::move(current_processing_pes_));
122  return true;
123  }
124  DCHECK_EQ(stream_type_, kStreamAudio);
125 
126  std::vector<uint8_t> audio_frame;
127 
128  // AAC is carried in ADTS.
129  if (adts_converter_) {
130  if (!adts_converter_->ConvertToADTS(sample.data(), sample.data_size(),
131  &audio_frame))
132  return false;
133  } else {
134  audio_frame.assign(sample.data(), sample.data() + sample.data_size());
135  }
136 
137  // TODO(rkuriowa): Put multiple samples in the PES packet to reduce # of PES
138  // packets.
139  current_processing_pes_->mutable_data()->swap(audio_frame);
140  current_processing_pes_->set_stream_id(audio_stream_id_);
141  pes_packets_.push_back(std::move(current_processing_pes_));
142  return true;
143 }
144 
146  return pes_packets_.size();
147 }
148 
149 std::unique_ptr<PesPacket> PesPacketGenerator::GetNextPesPacket() {
150  DCHECK(!pes_packets_.empty());
151  std::unique_ptr<PesPacket> pes = std::move(pes_packets_.front());
152  pes_packets_.pop_front();
153  return pes;
154 }
155 
157  return true;
158 }
159 
160 } // namespace mp2t
161 } // namespace media
162 } // namespace shaka
Holds audio stream information.
Class to hold a media sample.
Definition: media_sample.h:25
Abstract class holds stream information.
Definition: stream_info.h:71
Holds video stream information.
virtual bool PushSample(const MediaSample &sample)
virtual bool Initialize(const StreamInfo &stream)
PesPacketGenerator(int32_t transport_stream_timestamp_offset)
virtual std::unique_ptr< PesPacket > GetNextPesPacket()
Class that carries PES packet information.
Definition: pes_packet.h:20
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66