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