7 #include "packager/media/formats/webm/segmenter.h"
9 #include "packager/base/time/time.h"
10 #include "packager/media/base/audio_stream_info.h"
11 #include "packager/media/base/media_sample.h"
12 #include "packager/media/base/media_stream.h"
13 #include "packager/media/base/muxer_options.h"
14 #include "packager/media/base/stream_info.h"
15 #include "packager/media/base/video_stream_info.h"
16 #include "packager/media/event/muxer_listener.h"
17 #include "packager/media/event/progress_listener.h"
18 #include "packager/third_party/libwebm/src/mkvmuxerutil.hpp"
19 #include "packager/third_party/libwebm/src/webmids.hpp"
21 namespace edash_packager {
25 int64_t kTimecodeScale = 1000000;
26 int64_t kSecondsToNs = 1000000000L;
29 Segmenter::Segmenter(
const MuxerOptions& options)
30 : reference_frame_timestamp_(0),
33 muxer_listener_(NULL),
34 progress_listener_(NULL),
36 accumulated_progress_(0),
39 segment_payload_pos_(0),
40 cluster_length_sec_(0),
41 segment_length_sec_(0),
44 Segmenter::~Segmenter() {}
51 uint32_t max_sd_pixels,
52 double clear_lead_in_seconds) {
53 muxer_listener_ = muxer_listener;
55 clear_lead_ = clear_lead_in_seconds;
58 progress_target_ = info_->duration();
59 progress_listener_ = progress_listener;
61 const std::string version_string =
62 "https://github.com/google/edash-packager version " +
66 segment_info_.set_timecode_scale(kTimecodeScale);
67 segment_info_.set_writing_app(version_string.c_str());
72 segment_info_.set_duration(1);
76 if (encryption_key_source) {
77 status = InitializeEncryptor(encryption_key_source, max_sd_pixels);
83 switch (info_->stream_type()) {
85 status = CreateVideoTrack(static_cast<VideoStreamInfo*>(info_));
88 status = CreateAudioTrack(static_cast<AudioStreamInfo*>(info_));
91 NOTIMPLEMENTED() <<
"Not implemented for stream type: "
92 << info_->stream_type();
93 status =
Status(error::UNIMPLEMENTED,
"Not implemented for stream type");
98 return DoInitialize(writer.Pass());
102 Status status = WriteFrame(
true );
107 prev_sample_->pts() - first_timestamp_ + prev_sample_->duration();
108 segment_info_.set_duration(FromBMFFTimescale(duration));
113 if (sample_duration_ == 0) {
114 first_timestamp_ = sample->pts();
115 sample_duration_ = sample->duration();
129 bool wrote_frame =
false;
131 status = NewSegment(sample->pts());
136 status = WriteFrame(
true );
137 status.Update(NewSegment(sample->pts()));
138 segment_length_sec_ = 0;
139 cluster_length_sec_ = 0;
144 status = WriteFrame(
true );
145 status.Update(NewSubsegment(sample->pts()));
146 cluster_length_sec_ = 0;
151 status = WriteFrame(
false );
158 const bool encrypt_frame =
159 static_cast<double>(sample->pts() - first_timestamp_) /
160 info_->time_scale() >=
162 status = encryptor_->EncryptFrame(sample, encrypt_frame);
164 LOG(ERROR) <<
"Error encrypting frame.";
173 const double duration_sec =
174 static_cast<double>(sample->duration()) / info_->time_scale();
175 cluster_length_sec_ += duration_sec;
176 segment_length_sec_ += duration_sec;
178 prev_sample_ = sample;
183 return static_cast<float>(segment_info_.duration()) *
184 segment_info_.timecode_scale() / kSecondsToNs;
187 uint64_t Segmenter::FromBMFFTimescale(uint64_t time_timescale) {
189 const int64_t time_ns =
190 kSecondsToNs * time_timescale / info_->time_scale();
191 return time_ns / segment_info_.timecode_scale();
194 uint64_t Segmenter::FromWebMTimecode(uint64_t time_webm_timecode) {
196 const int64_t time_ns = time_webm_timecode * segment_info_.timecode_scale();
197 return time_ns * info_->time_scale() / kSecondsToNs;
201 Status error_status(error::FILE_FAILURE,
"Error writing segment header.");
203 if (!WriteEbmlHeader(writer))
206 if (WriteID(writer, mkvmuxer::kMkvSegment) != 0)
209 const uint64_t segment_size_size = 8;
210 segment_payload_pos_ = writer->
Position() + segment_size_size;
213 if (WriteUIntSize(writer, file_size - segment_payload_pos_,
214 segment_size_size) != 0)
216 if (!seek_head_.Write(writer))
219 if (SerializeInt(writer, mkvmuxer::kEbmlUnknownValue, segment_size_size) !=
223 if (!seek_head_.WriteVoid(writer))
227 if (!segment_info_.Write(writer))
230 if (!tracks_.Write(writer))
236 Status Segmenter::SetCluster(uint64_t start_webm_timecode,
239 const uint64_t scale = segment_info_.timecode_scale();
240 cluster_.reset(
new mkvmuxer::Cluster(start_webm_timecode, position, scale));
241 cluster_->Init(writer);
246 accumulated_progress_ += progress;
247 if (!progress_listener_ || progress_target_ == 0)
252 if (accumulated_progress_ >= progress_target_) {
255 progress_listener_->
OnProgress(static_cast<double>(accumulated_progress_) /
262 unsigned int seed = 0;
263 mkvmuxer::VideoTrack* track =
new mkvmuxer::VideoTrack(&seed);
265 return Status(error::INTERNAL_ERROR,
"Failed to create video track.");
267 if (info->codec() == kCodecVP8) {
268 track->set_codec_id(mkvmuxer::Tracks::kVp8CodecId);
269 }
else if (info->codec() == kCodecVP9) {
270 track->set_codec_id(mkvmuxer::Tracks::kVp9CodecId);
272 LOG(ERROR) <<
"Only VP8 and VP9 video codec is supported.";
273 return Status(error::UNIMPLEMENTED,
274 "Only VP8 and VP9 video codecs are supported.");
277 track->set_uid(info->track_id());
278 if (!info->language().empty())
279 track->set_language(info->language().c_str());
280 track->set_type(mkvmuxer::Tracks::kVideo);
281 track->set_width(info->width());
282 track->set_height(info->height());
283 track->set_display_height(info->height());
284 track->set_display_width(info->width() * info->
pixel_width() /
288 encryptor_->AddTrackInfo(track);
290 tracks_.AddTrack(track, info->track_id());
291 track_id_ = track->number();
295 Status Segmenter::CreateAudioTrack(AudioStreamInfo* info) {
297 unsigned int seed = 0;
298 mkvmuxer::AudioTrack* track =
new mkvmuxer::AudioTrack(&seed);
300 return Status(error::INTERNAL_ERROR,
"Failed to create audio track.");
302 if (info->codec() == kCodecOpus) {
303 track->set_codec_id(mkvmuxer::Tracks::kOpusCodecId);
304 }
else if (info->codec() == kCodecVorbis) {
305 track->set_codec_id(mkvmuxer::Tracks::kVorbisCodecId);
307 LOG(ERROR) <<
"Only Vorbis and Opus audio codec is supported.";
308 return Status(error::UNIMPLEMENTED,
309 "Only Vorbis and Opus audio codecs are supported.");
311 if (!track->SetCodecPrivate(info->extra_data().data(),
312 info->extra_data().size())) {
313 return Status(error::INTERNAL_ERROR,
314 "Private codec data required for audio streams");
317 track->set_uid(info->track_id());
318 if (!info->language().empty())
319 track->set_language(info->language().c_str());
320 track->set_type(mkvmuxer::Tracks::kAudio);
321 track->set_sample_rate(info->sampling_frequency());
322 track->set_channels(info->num_channels());
325 encryptor_->AddTrackInfo(track);
327 tracks_.AddTrack(track, info->track_id());
328 track_id_ = track->number();
332 Status Segmenter::InitializeEncryptor(KeySource* key_source,
333 uint32_t max_sd_pixels) {
334 encryptor_.reset(
new Encryptor());
335 switch (info_->stream_type()) {
337 VideoStreamInfo* video_info =
static_cast<VideoStreamInfo*
>(info_);
338 uint32_t pixels = video_info->width() * video_info->height();
339 KeySource::TrackType type = (pixels > max_sd_pixels)
340 ? KeySource::TRACK_TYPE_HD
341 : KeySource::TRACK_TYPE_SD;
342 return encryptor_->Initialize(muxer_listener_, type, key_source);
345 return encryptor_->Initialize(
346 muxer_listener_, KeySource::TrackType::TRACK_TYPE_AUDIO, key_source);
353 Status Segmenter::WriteFrame(
bool write_duration) {
357 mkvmuxer::Frame frame;
359 if (!frame.Init(prev_sample_->data(), prev_sample_->data_size())) {
360 return Status(error::MUXER_FAILURE,
361 "Error adding sample to segment: Frame::Init failed");
364 if (write_duration) {
365 const uint64_t duration_ns =
366 prev_sample_->duration() * kSecondsToNs / info_->time_scale();
367 frame.set_duration(duration_ns);
369 frame.set_is_key(prev_sample_->is_key_frame());
370 frame.set_timestamp(prev_sample_->pts() * kSecondsToNs / info_->time_scale());
371 frame.set_track_number(track_id_);
373 if (prev_sample_->side_data_size() > 0) {
374 uint64_t block_add_id;
377 CHECK_GT(prev_sample_->side_data_size(),
sizeof(block_add_id));
378 memcpy(&block_add_id, prev_sample_->side_data(),
sizeof(block_add_id));
379 if (!frame.AddAdditionalData(
380 prev_sample_->side_data() +
sizeof(block_add_id),
381 prev_sample_->side_data_size() -
sizeof(block_add_id),
384 error::MUXER_FAILURE,
385 "Error adding sample to segment: Frame::AddAditionalData Failed");
389 if (!prev_sample_->is_key_frame() && !frame.CanBeSimpleBlock()) {
390 const int64_t timestamp_ns =
391 reference_frame_timestamp_ * kSecondsToNs / info_->time_scale();
392 frame.set_reference_block_timestamp(timestamp_ns);
395 if (!cluster_->AddFrame(&frame)) {
396 return Status(error::MUXER_FAILURE,
397 "Error adding sample to segment: Cluster::AddFrame failed");
403 reference_frame_timestamp_ = prev_sample_->pts();