Shaka Packager SDK
Loading...
Searching...
No Matches
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
25namespace shaka {
26namespace media {
27namespace mp2t {
28
29namespace {
30const uint8_t kVideoStreamId = 0xE0;
31const uint8_t kAacAudioStreamId = 0xC0;
32const uint8_t kAc3AudioStreamId = 0xBD; // AC3 uses private stream 1 id.
33const double kTsTimescale = 90000.0;
34} // namespace
35
37 int32_t transport_stream_timestamp_offset)
38 : transport_stream_timestamp_offset_(transport_stream_timestamp_offset) {}
39
40PesPacketGenerator::~PesPacketGenerator() {}
41
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
149std::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.
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.