1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "media/base/decoder_buffer_queue.h"
6
7#include "base/logging.h"
8#include "base/numerics/safe_conversions.h"
9#include "media/base/buffers.h"
10#include "media/base/decoder_buffer.h"
11
12namespace media {
13
14DecoderBufferQueue::DecoderBufferQueue()
15    : earliest_valid_timestamp_(kNoTimestamp()),
16      data_size_(0) {
17}
18
19DecoderBufferQueue::~DecoderBufferQueue() {}
20
21void DecoderBufferQueue::Push(const scoped_refptr<DecoderBuffer>& buffer) {
22  CHECK(!buffer->end_of_stream());
23
24  queue_.push_back(buffer);
25
26  // TODO(damienv): Remove the cast here and in every place in this file
27  // when DecoderBuffer::data_size is modified to return a size_t.
28  data_size_ += base::checked_cast<size_t, int>(buffer->data_size());
29
30  // TODO(scherkus): FFmpeg returns some packets with no timestamp after
31  // seeking. Fix and turn this into CHECK(). See http://crbug.com/162192
32  if (buffer->timestamp() == kNoTimestamp()) {
33    DVLOG(1) << "Buffer has no timestamp";
34    return;
35  }
36
37  if (earliest_valid_timestamp_ == kNoTimestamp()) {
38    earliest_valid_timestamp_ = buffer->timestamp();
39  }
40
41  if (buffer->timestamp() < earliest_valid_timestamp_) {
42    DVLOG(1)
43        << "Out of order timestamps: "
44        << buffer->timestamp().InMicroseconds()
45        << " vs. "
46        << earliest_valid_timestamp_.InMicroseconds();
47    return;
48  }
49
50  earliest_valid_timestamp_ = buffer->timestamp();
51  in_order_queue_.push_back(buffer);
52}
53
54scoped_refptr<DecoderBuffer> DecoderBufferQueue::Pop() {
55  scoped_refptr<DecoderBuffer> buffer = queue_.front();
56  queue_.pop_front();
57
58  size_t buffer_data_size =
59      base::checked_cast<size_t, int>(buffer->data_size());
60  DCHECK_LE(buffer_data_size, data_size_);
61  data_size_ -= buffer_data_size;
62
63  if (!in_order_queue_.empty() &&
64      in_order_queue_.front().get() == buffer.get()) {
65    in_order_queue_.pop_front();
66  }
67
68  return buffer;
69}
70
71void DecoderBufferQueue::Clear() {
72  queue_.clear();
73  data_size_ = 0;
74  in_order_queue_.clear();
75  earliest_valid_timestamp_ = kNoTimestamp();
76}
77
78bool DecoderBufferQueue::IsEmpty() {
79  return queue_.empty();
80}
81
82base::TimeDelta DecoderBufferQueue::Duration() {
83  if (in_order_queue_.size() < 2)
84    return base::TimeDelta();
85
86  base::TimeDelta start = in_order_queue_.front()->timestamp();
87  base::TimeDelta end = in_order_queue_.back()->timestamp();
88  return end - start;
89}
90
91}  // namespace media
92