Use Common Hint

Use a common hint for all stream states as the hint is always
updated when we get a new cue event. Cue events are only gotten
when be pass the hint, so there should only need to be one hint.

Change-Id: I0838110b9b10325a9e99f8fca0b11f0a6b48f8a0
This commit is contained in:
Aaron Vaage 2018-05-08 16:19:08 -07:00
parent 2ea347f45c
commit df19a48aa0
2 changed files with 22 additions and 29 deletions

View File

@ -56,6 +56,11 @@ CueAlignmentHandler::CueAlignmentHandler(SyncPointQueue* sync_points)
Status CueAlignmentHandler::InitializeInternal() {
sync_points_->AddThread();
stream_states_.resize(num_input_streams());
// Get the first hint for the stream. Use a negative hint so that if there is
// suppose to be a sync point at zero, we will still respect it.
hint_ = sync_points_->GetHint(-1);
return Status::OK;
}
@ -106,9 +111,6 @@ Status CueAlignmentHandler::OnStreamInfo(std::unique_ptr<StreamData> data) {
// Keep a copy of the stream info so that we can check type and check
// timescale.
stream_state.info = data->stream_info;
// Get the first hint for the stream. Use a negative hint so that if there is
// suppose to be a sync point at zero, we will still respect it.
stream_state.next_cue_hint = sync_points_->GetHint(-1);
return Dispatch(std::move(data));
}
@ -129,8 +131,7 @@ Status CueAlignmentHandler::OnSample(std::unique_ptr<StreamData> sample) {
if (stream_state.info->stream_type() == kStreamVideo) {
const double sample_time = TimeInSeconds(*stream_state.info, *sample);
if (sample->media_sample->is_key_frame() &&
sample_time >= stream_state.next_cue_hint) {
if (sample->media_sample->is_key_frame() && sample_time >= hint_) {
std::shared_ptr<const CueEvent> next_sync =
sync_points_->PromoteAt(sample_time);
if (!next_sync) {
@ -162,14 +163,7 @@ Status CueAlignmentHandler::OnSample(std::unique_ptr<StreamData> sample) {
// to wait for all streams to converge on a hint so that we can get the next
// sync point.
if (EveryoneWaitingAtHint()) {
// All streams should have the same hint right now.
const double next_cue_hint = stream_state.next_cue_hint;
for (const StreamState& stream_state : stream_states_) {
DCHECK_EQ(next_cue_hint, stream_state.next_cue_hint);
}
std::shared_ptr<const CueEvent> next_sync =
sync_points_->GetNext(next_cue_hint);
std::shared_ptr<const CueEvent> next_sync = sync_points_->GetNext(hint_);
if (!next_sync) {
// This happens only if the job is cancelled.
return Status(error::CANCELLED, "SyncPointQueue is cancelled.");
@ -186,8 +180,8 @@ Status CueAlignmentHandler::OnSample(std::unique_ptr<StreamData> sample) {
Status CueAlignmentHandler::UseNewSyncPoint(
std::shared_ptr<const CueEvent> new_sync) {
const double new_hint = sync_points_->GetHint(new_sync->time_in_seconds);
DCHECK_GT(new_hint, new_sync->time_in_seconds);
hint_ = sync_points_->GetHint(new_sync->time_in_seconds);
DCHECK_GT(hint_, new_sync->time_in_seconds);
Status status;
for (StreamState& stream_state : stream_states_) {
@ -202,16 +196,13 @@ Status CueAlignmentHandler::UseNewSyncPoint(
return Status(error::INVALID_ARGUMENT, "Cue events too close together");
}
// Add the cue and update the hint. The cue will always be used over the
// hint, so hint should always be greater than the latest cue.
stream_state.cue = new_sync;
stream_state.next_cue_hint = new_hint;
while (status.ok() && !stream_state.samples.empty()) {
std::unique_ptr<StreamData>& sample = stream_state.samples.front();
const double sample_time_in_seconds =
TimeInSeconds(*stream_state.info, *sample);
if (sample_time_in_seconds >= stream_state.next_cue_hint) {
if (sample_time_in_seconds >= hint_) {
DCHECK(!stream_state.cue);
break;
}
@ -249,7 +240,7 @@ Status CueAlignmentHandler::AcceptSample(std::unique_ptr<StreamData> sample,
if (stream_state->samples.empty()) {
const double sample_time_in_seconds =
TimeInSeconds(*stream_state->info, *sample);
if (sample_time_in_seconds < stream_state->next_cue_hint) {
if (sample_time_in_seconds < hint_) {
Status status;
if (stream_state->cue) {
status.Update(DispatchCueIfNeeded(stream_index, sample_time_in_seconds,
@ -280,7 +271,7 @@ Status CueAlignmentHandler::DispatchCueIfNeeded(
DCHECK(stream_state->cue);
if (next_sample_time_in_seconds < stream_state->cue->time_in_seconds)
return Status::OK;
DCHECK_LT(stream_state->cue->time_in_seconds, stream_state->next_cue_hint);
DCHECK_LT(stream_state->cue->time_in_seconds, hint_);
return DispatchCueEvent(stream_index, std::move(stream_state->cue));
}

View File

@ -44,14 +44,6 @@ class CueAlignmentHandler : public MediaHandler {
// it is not set, the next cue is not determined.
// This is set but not really used by video stream.
std::shared_ptr<const CueEvent> cue;
// If |cue| is set, this is the hint for the cue after |cue|, i.e. next next
// cue; otherwise this is the hint for the next cue. This holds the time in
// seconds of the scheduled (unpromoted) next or next next cue's time. This
// is essentially the barrier for the sample stream. Non video samples after
// this barrier must wait until the |cue| is determined and thus the next
// hint to be determined; video samples will promote the hint to cue when
// seeing the first key frame after |next_cue_hint|.
double next_cue_hint = 0;
};
// MediaHandler overrides.
@ -80,6 +72,16 @@ class CueAlignmentHandler : public MediaHandler {
SyncPointQueue* const sync_points_ = nullptr;
std::vector<StreamState> stream_states_;
// A common hint used by all streams. When a new cue is given to all streams,
// the hint will be updated. The hint will always be larger than any cue. The
// hint represents the min time in seconds for the next cue appear. The hints
// are based off the un-promoted cue event times in |sync_points_|.
//
// When a video stream passes the hint, it will promote the corresponding cue
// event. If all streams get to the hint and there are no video streams, the
// thread will block until |sync_points_| gives back a promoted cue event.
double hint_;
};
} // namespace media