// Minimum duration of syncing state. It serves the role to ensure
// that overlay and texture output is synchronized on display.
constexpr static auto kMinimumSyncingDuration = base::Milliseconds(300);
+
+size_t MaxForwardReferenceFrameDistance(MediaVideoCodec codec) {
+ switch (codec) {
+ case MediaVideoCodec::kCodecUnknown:
+ case MediaVideoCodec::kCodecVP8:
+ case MediaVideoCodec::kCodecVP9:
+ case MediaVideoCodec::kCodecAV1:
+ case MediaVideoCodec::kCodecMJPEG:
+ // Those codecs don't have bidirectional frames.
+ return 0;
+ // Both H264 and HEVC have bidirectional decoded picture buffering (DPB)
+ // limited to 16. It means that at most that number of frames might be
+ // hold as an reference for frame decoding.
+ case MediaVideoCodec::kCodecH264:
+ case MediaVideoCodec::kCodecHEVC:
+ return 16;
+ }
+ return 0;
+}
} // namespace
void DecodedCollectionOnGpu::NotifyModeChange(gfx::VideoOutputMode mode) {
// error of 1us (internal unit of base::TimeDelta).
// Low delay mode does not have any bi-directional frames, so decoding order
// is also rendering order.
- if (!low_delay_ && !ranges_.IsInRange(decoding_request.timestamp)) {
+ if (CanHaveBidirectionalFrames() &&
+ !ranges_.IsInRange(decoding_request.timestamp)) {
+ return false;
+ }
+
+ if (decoding_request.end_of_stream) {
return false;
}
return true;
}
+bool TTvdVideoDecoderImpl::CanHaveBidirectionalFrames() const {
+ if (low_delay_) {
+ return false;
+ }
+ return MaxForwardReferenceFrameDistance(codec_) != 0;
+}
+
void TTvdVideoDecoderImpl::TriggerLazyFrames() {
// We want to return frames in proper order (of non-descending timestamp)
// and they are stored according to decode timestamp. At first, gather all
// frames that can be returned as lazy frames.
std::vector<base::TimeDelta> frames_timestamp;
- for (auto it = decoding_requests_.begin(); it != decoding_requests_.end();
- ++it) {
- if (!ShouldTriggerLazyFrame(*it)) {
- continue;
+ for (const auto& decoding_request : decoding_requests_) {
+ if (ShouldTriggerLazyFrame(decoding_request)) {
+ frames_timestamp.push_back(decoding_request.timestamp);
}
+ }
+ if (frames_timestamp.empty() && CanHaveBidirectionalFrames() &&
+ decoding_requests_.size() >= MaxForwardReferenceFrameDistance(codec_) &&
+ std::none_of(decoding_requests_.begin(), decoding_requests_.end(),
+ [](const DecodingRequest& decoding_request) {
+ return decoding_request.lazy_frame_returned;
+ })) {
+ auto it = std::min_element(
+ decoding_requests_.begin(), decoding_requests_.end(),
+ [](const DecodingRequest& a, const DecodingRequest& b) {
+ return a.timestamp < b.timestamp;
+ });
+ TIZEN_MEDIA_LOG_ASSERT(it != decoding_requests_.end());
+ TIZEN_MEDIA_LOG(VERBOSE)
+ << "We should trigger lazy frame for: " << it->timestamp;
+ ranges_.FillGapUpTo(it->timestamp);
frames_timestamp.push_back(it->timestamp);
}
// sort and return.
std::vector<scoped_refptr<VideoFrame>> video_frames;
for (auto it = decoding_requests_.begin(); it != decoding_requests_.end();) {
- if (!ShouldTriggerLazyFrame(*it)) {
- ++it;
- continue;
- }
-
- if (it->end_of_stream) {
- ++it;
- continue;
- }
-
- if (ttvd_decoded_frame_pool_.empty()) {
- needs_new_ttvd_decoded_frame = true;
- break;
- }
-
const base::TimeDelta timestamp = it->timestamp;
if (std::find(frames_timestamp.begin(), frames_timestamp.end(),
// buffers are rejected in |Decode| method.
TIZEN_MEDIA_LOG_ASSERT(buffer->timestamp() != kNoTimestamp);
- // Calculating ranges makes no sense for RTC, since it cannot contain
- // bidirectional frames.
- if (!config_.is_rtc()) {
+ // Calculating ranges makes no sense when there won't be bidirectional frames.
+ if (CanHaveBidirectionalFrames()) {
ranges_.Insert(*buffer);
}
callbacks.switch_cb = base::BindPostTaskToCurrentDefault(base::BindRepeating(
&TTvdVideoDecoderImpl::SwitchDecoder, weak_factory_.GetWeakPtr()));
- MediaVideoCodec codec = VideoCodecToMediaVideoCodec(config_.codec());
- if (codec == MediaVideoCodec::kCodecUnknown) {
+ codec_ = VideoCodecToMediaVideoCodec(config_.codec());
+ if (codec_ == MediaVideoCodec::kCodecUnknown) {
TIZEN_MEDIA_LOG(ERROR) << "Not supported video codec: " << config_.codec();
}
// return that valid resolutions (e.g 3840x2176) are not supported on
// several boards.
auto decoder = DecoderPromotion::GetInstance()->SelectDecoder(
- codec, config_.level(), config_.visible_rect().size(),
+ codec_, config_.level(), config_.visible_rect().size(),
config_.chroma_sampling, config_.bit_depth, GetLatencyMode(),
std::move(callbacks), &workarounds_);
if (!decoder) {
// It might be also changed be calls to |Initialize|.
ExtendedVideoDecoderConfig config_;
+ MediaVideoCodec codec_;
+
// Determines whether decoder should return decoded frame without
// further |Decode| calls. Note that B-frames are not allowed if
// it is enabled.
bool ShouldTriggerLazyFrame(const DecodingRequest& decoding_request) const;
+ // Returns information whether current configuration can have
+ // bidirectional frames.
+ bool CanHaveBidirectionalFrames() const;
+
// Holds pending video frame decodings, so the onces that were
// already accepted by Decode method on decoder thread,
// but no output (media::VideoFrame) was triggered for them.
std::pair<base::TimeDelta, ProcessingAction> last_processing_frame_;
// Ranges of video corresponding data that were accepted by decoder.
+ // Note that it should be used only when bidirectional frames are in stream,
+ // |CanHaveBidirectionalFrames| should be used to check that.
LazyFrameRanges ranges_;
// Rendering callback gathered from overlay system. It should be