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)
32 muxer_listener_(NULL),
33 progress_listener_(NULL),
35 accumulated_progress_(0),
38 segment_payload_pos_(0),
39 cluster_length_sec_(0),
40 segment_length_sec_(0),
43 Segmenter::~Segmenter() {}
50 muxer_listener_ = muxer_listener;
54 progress_target_ = stream_->info()->duration();
55 progress_listener_ = progress_listener;
58 segment_info_.set_timecode_scale(kTimecodeScale);
59 if (options().single_segment) {
62 segment_info_.set_duration(1);
67 switch (stream_->info()->stream_type()) {
69 status = CreateVideoTrack(
70 static_cast<VideoStreamInfo*>(stream_->info().get()));
73 status = CreateAudioTrack(
74 static_cast<AudioStreamInfo*>(stream_->info().get()));
77 NOTIMPLEMENTED() <<
"Not implemented for stream type: "
78 << stream_->info()->stream_type();
79 status =
Status(error::UNIMPLEMENTED,
"Not implemented for stream type");
84 return DoInitialize(writer.Pass());
88 segment_info_.set_duration(FromBMFFTimescale(total_duration_));
93 if (sample_duration_ == 0) {
94 sample_duration_ = sample->duration();
104 status = NewSegment(sample->pts());
107 status = NewSegment(sample->pts());
108 segment_length_sec_ = 0;
109 cluster_length_sec_ = 0;
113 status = NewSubsegment(sample->pts());
114 cluster_length_sec_ = 0;
120 const int64_t time_ns =
121 sample->pts() * kSecondsToNs / stream_->info()->time_scale();
122 if (!cluster_->AddFrame(sample->data(), sample->data_size(), track_id_,
123 time_ns, sample->is_key_frame())) {
124 LOG(ERROR) <<
"Error adding sample to segment.";
125 return Status(error::FILE_FAILURE,
"Error adding sample to segment.");
127 const double duration_sec =
128 static_cast<double>(sample->duration()) / stream_->info()->time_scale();
129 cluster_length_sec_ += duration_sec;
130 segment_length_sec_ += duration_sec;
131 total_duration_ += sample->duration();
137 return static_cast<float>(segment_info_.duration()) *
138 segment_info_.timecode_scale() / kSecondsToNs;
141 uint64_t Segmenter::FromBMFFTimescale(uint64_t time_timescale) {
143 const int64_t time_ns =
144 kSecondsToNs * time_timescale / stream_->info()->time_scale();
145 return time_ns / segment_info_.timecode_scale();
148 uint64_t Segmenter::FromWebMTimecode(uint64_t time_webm_timecode) {
150 const int64_t time_ns = time_webm_timecode * segment_info_.timecode_scale();
151 return time_ns * stream_->info()->time_scale() / kSecondsToNs;
155 Status error_status(error::FILE_FAILURE,
"Error writing segment header.");
157 if (!WriteEbmlHeader(writer))
160 if (WriteID(writer, mkvmuxer::kMkvSegment) != 0)
163 const uint64_t segment_size_size = 8;
164 segment_payload_pos_ = writer->
Position() + segment_size_size;
167 if (WriteUIntSize(writer, file_size - segment_payload_pos_,
168 segment_size_size) != 0)
170 if (!seek_head_.Write(writer))
173 if (SerializeInt(writer, mkvmuxer::kEbmlUnknownValue, segment_size_size) !=
177 if (!seek_head_.WriteVoid(writer))
181 if (!segment_info_.Write(writer))
184 if (!tracks_.Write(writer))
190 Status Segmenter::SetCluster(uint64_t start_webm_timecode,
193 const uint64_t scale = segment_info_.timecode_scale();
194 cluster_.reset(
new mkvmuxer::Cluster(start_webm_timecode, position, scale));
195 cluster_->Init(writer);
200 accumulated_progress_ += progress;
201 if (!progress_listener_ || progress_target_ == 0)
206 if (accumulated_progress_ >= progress_target_) {
209 progress_listener_->
OnProgress(static_cast<double>(accumulated_progress_) /
216 unsigned int seed = 0;
217 mkvmuxer::VideoTrack* track =
new mkvmuxer::VideoTrack(&seed);
219 return Status(error::INTERNAL_ERROR,
"Failed to create video track.");
221 if (info->codec() == kCodecVP8) {
222 track->set_codec_id(mkvmuxer::Tracks::kVp8CodecId);
223 }
else if (info->codec() == kCodecVP9) {
224 track->set_codec_id(mkvmuxer::Tracks::kVp9CodecId);
226 LOG(ERROR) <<
"Only VP8 and VP9 video codec is supported.";
227 return Status(error::UNIMPLEMENTED,
228 "Only VP8 and VP9 video codecs are supported.");
231 track->set_uid(info->track_id());
232 track->set_type(mkvmuxer::Tracks::kVideo);
233 track->set_width(info->width());
234 track->set_height(info->height());
235 track->set_display_height(info->height());
236 track->set_display_width(info->width() * info->
pixel_width() /
238 track->set_language(info->language().c_str());
240 tracks_.AddTrack(track, info->track_id());
241 track_id_ = track->number();
245 Status Segmenter::CreateAudioTrack(AudioStreamInfo* info) {
247 unsigned int seed = 0;
248 mkvmuxer::AudioTrack* track =
new mkvmuxer::AudioTrack(&seed);
250 return Status(error::INTERNAL_ERROR,
"Failed to create audio track.");
252 if (info->codec() == kCodecOpus) {
253 track->set_codec_id(mkvmuxer::Tracks::kOpusCodecId);
254 }
else if (info->codec() == kCodecVorbis) {
255 track->set_codec_id(mkvmuxer::Tracks::kVorbisCodecId);
257 LOG(ERROR) <<
"Only Vorbis and Opus audio codec is supported.";
258 return Status(error::UNIMPLEMENTED,
259 "Only Vorbis and Opus audio codecs are supported.");
262 track->set_uid(info->track_id());
263 track->set_language(info->language().c_str());
264 track->set_type(mkvmuxer::Tracks::kAudio);
265 track->set_sample_rate(info->sampling_frequency());
266 track->set_channels(info->num_channels());
268 tracks_.AddTrack(track, info->track_id());
269 track_id_ = track->number();