7 #include <packager/media/formats/packed_audio/packed_audio_segmenter.h>
11 #include <absl/log/check.h>
13 #include <packager/macros/status.h>
14 #include <packager/media/base/id3_tag.h>
15 #include <packager/media/base/media_sample.h>
16 #include <packager/media/codecs/aac_audio_specific_config.h>
17 #include <packager/media/codecs/hls_audio_util.h>
22 std::string TimestampToString(int64_t timestamp) {
26 timestamp &= 0x1FFFFFFFFull;
29 buffer.AppendInt(timestamp);
30 return std::string(buffer.Buffer(), buffer.Buffer() + buffer.Size());
35 int32_t transport_stream_timestamp_offset)
36 : transport_stream_timestamp_offset_(transport_stream_timestamp_offset) {}
38 PackedAudioSegmenter::~PackedAudioSegmenter() =
default;
41 const StreamType stream_type = stream_info.stream_type();
42 if (stream_type != StreamType::kStreamAudio) {
43 LOG(ERROR) <<
"PackedAudioSegmenter cannot handle stream type "
45 return Status(error::MUXER_FAILURE,
"Unsupported stream type.");
48 codec_ = stream_info.codec();
49 audio_codec_config_ = stream_info.codec_config();
50 timescale_scale_ = kPackedAudioTimescale / stream_info.time_scale();
52 if (codec_ == kCodecAAC) {
53 adts_converter_ = CreateAdtsConverter();
54 if (!adts_converter_->Parse(audio_codec_config_)) {
55 return Status(error::MUXER_FAILURE,
"Invalid audio codec configuration.");
63 if (sample.is_encrypted() && audio_setup_information_.empty())
64 RETURN_IF_ERROR(EncryptionAudioSetup(sample));
66 if (start_of_new_segment_) {
67 RETURN_IF_ERROR(StartNewSegment(sample));
68 start_of_new_segment_ =
false;
71 if (adts_converter_) {
72 std::vector<uint8_t> audio_frame;
73 if (!adts_converter_->ConvertToADTS(sample.data(), sample.data_size(),
75 return Status(error::MUXER_FAILURE,
"Failed to convert to ADTS.");
76 segment_buffer_.AppendArray(audio_frame.data(), audio_frame.size());
78 segment_buffer_.AppendArray(sample.data(), sample.data_size());
84 start_of_new_segment_ =
true;
89 return timescale_scale_;
92 std::unique_ptr<AACAudioSpecificConfig>
93 PackedAudioSegmenter::CreateAdtsConverter() {
97 std::unique_ptr<Id3Tag> PackedAudioSegmenter::CreateId3Tag() {
98 return std::unique_ptr<Id3Tag>(
new Id3Tag);
101 Status PackedAudioSegmenter::EncryptionAudioSetup(
const MediaSample& sample) {
104 const uint8_t* audio_setup_data = audio_codec_config_.data();
105 size_t audio_setup_data_size = audio_codec_config_.size();
106 if (codec_ == kCodecAC3) {
111 const size_t kSetupDataSize = 10u;
112 if (sample.data_size() < kSetupDataSize) {
113 LOG(ERROR) <<
"Sample is too small for AC3: " << sample.data_size();
114 return Status(error::MUXER_FAILURE,
"Sample is too small for AC3.");
116 audio_setup_data = sample.data();
117 audio_setup_data_size = kSetupDataSize;
121 if (!WriteAudioSetupInformation(codec_, audio_setup_data,
122 audio_setup_data_size, &buffer)) {
123 return Status(error::MUXER_FAILURE,
124 "Failed to write audio setup information.");
126 audio_setup_information_.assign(buffer.Buffer(),
127 buffer.Buffer() + buffer.Size());
131 Status PackedAudioSegmenter::StartNewSegment(
const MediaSample& sample) {
132 segment_buffer_.Clear();
135 sample.pts() * timescale_scale_ + transport_stream_timestamp_offset_;
137 LOG(ERROR) <<
"Seeing negative timestamp " << pts
138 <<
" after applying offset "
139 << transport_stream_timestamp_offset_
140 <<
". Please check if it is expected. Adjust "
141 "--transport_stream_timestamp_offset_ms if needed.";
142 return Status(error::MUXER_FAILURE,
"Unsupported negative timestamp.");
146 std::unique_ptr<Id3Tag> id3_tag = CreateId3Tag();
147 id3_tag->AddPrivateFrame(kTimestampOwnerIdentifier, TimestampToString(pts));
148 if (!audio_setup_information_.empty()) {
149 id3_tag->AddPrivateFrame(kAudioDescriptionOwnerIdentifier,
150 audio_setup_information_);
152 CHECK(id3_tag->WriteToBuffer(&segment_buffer_));
All the methods that are virtual are virtual for mocking.