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/stream_parser_buffer.h"
6
7#include "base/logging.h"
8#include "media/base/buffers.h"
9
10namespace media {
11
12static scoped_refptr<StreamParserBuffer> CopyBuffer(
13    const StreamParserBuffer& buffer) {
14  if (buffer.end_of_stream())
15    return StreamParserBuffer::CreateEOSBuffer();
16
17  scoped_refptr<StreamParserBuffer> copied_buffer =
18      StreamParserBuffer::CopyFrom(buffer.data(),
19                                   buffer.data_size(),
20                                   buffer.side_data(),
21                                   buffer.side_data_size(),
22                                   buffer.IsKeyframe(),
23                                   buffer.type(),
24                                   buffer.track_id());
25  copied_buffer->SetDecodeTimestamp(buffer.GetDecodeTimestamp());
26  copied_buffer->SetConfigId(buffer.GetConfigId());
27  copied_buffer->set_timestamp(buffer.timestamp());
28  copied_buffer->set_duration(buffer.duration());
29  copied_buffer->set_discard_padding(buffer.discard_padding());
30  copied_buffer->set_splice_timestamp(buffer.splice_timestamp());
31  const DecryptConfig* decrypt_config = buffer.decrypt_config();
32  if (decrypt_config) {
33    copied_buffer->set_decrypt_config(
34        make_scoped_ptr(new DecryptConfig(decrypt_config->key_id(),
35                                          decrypt_config->iv(),
36                                          decrypt_config->subsamples())));
37  }
38
39  return copied_buffer;
40}
41
42scoped_refptr<StreamParserBuffer> StreamParserBuffer::CreateEOSBuffer() {
43  return make_scoped_refptr(new StreamParserBuffer(NULL, 0, NULL, 0, false,
44                                                   DemuxerStream::UNKNOWN, 0));
45}
46
47scoped_refptr<StreamParserBuffer> StreamParserBuffer::CopyFrom(
48    const uint8* data, int data_size, bool is_keyframe, Type type,
49    TrackId track_id) {
50  return make_scoped_refptr(
51      new StreamParserBuffer(data, data_size, NULL, 0, is_keyframe, type,
52                             track_id));
53}
54
55scoped_refptr<StreamParserBuffer> StreamParserBuffer::CopyFrom(
56    const uint8* data, int data_size,
57    const uint8* side_data, int side_data_size,
58    bool is_keyframe, Type type, TrackId track_id) {
59  return make_scoped_refptr(
60      new StreamParserBuffer(data, data_size, side_data, side_data_size,
61                             is_keyframe, type, track_id));
62}
63
64base::TimeDelta StreamParserBuffer::GetDecodeTimestamp() const {
65  if (decode_timestamp_ == kNoTimestamp())
66    return timestamp();
67  return decode_timestamp_;
68}
69
70void StreamParserBuffer::SetDecodeTimestamp(base::TimeDelta timestamp) {
71  decode_timestamp_ = timestamp;
72  if (preroll_buffer_)
73    preroll_buffer_->SetDecodeTimestamp(timestamp);
74}
75
76StreamParserBuffer::StreamParserBuffer(const uint8* data, int data_size,
77                                       const uint8* side_data,
78                                       int side_data_size, bool is_keyframe,
79                                       Type type, TrackId track_id)
80    : DecoderBuffer(data, data_size, side_data, side_data_size),
81      is_keyframe_(is_keyframe),
82      decode_timestamp_(kNoTimestamp()),
83      config_id_(kInvalidConfigId),
84      type_(type),
85      track_id_(track_id) {
86  // TODO(scherkus): Should DataBuffer constructor accept a timestamp and
87  // duration to force clients to set them? Today they end up being zero which
88  // is both a common and valid value and could lead to bugs.
89  if (data) {
90    set_duration(kNoTimestamp());
91  }
92}
93
94StreamParserBuffer::~StreamParserBuffer() {}
95
96int StreamParserBuffer::GetConfigId() const {
97  return config_id_;
98}
99
100void StreamParserBuffer::SetConfigId(int config_id) {
101  config_id_ = config_id;
102  if (preroll_buffer_)
103    preroll_buffer_->SetConfigId(config_id);
104}
105
106void StreamParserBuffer::ConvertToSpliceBuffer(
107    const BufferQueue& pre_splice_buffers) {
108  DCHECK(splice_buffers_.empty());
109  DCHECK(!end_of_stream());
110
111  // Make a copy of this first, before making any changes.
112  scoped_refptr<StreamParserBuffer> overlapping_buffer = CopyBuffer(*this);
113  overlapping_buffer->set_splice_timestamp(kNoTimestamp());
114
115  const scoped_refptr<StreamParserBuffer>& first_splice_buffer =
116      pre_splice_buffers.front();
117
118  // Ensure the given buffers are actually before the splice point.
119  DCHECK(first_splice_buffer->timestamp() <= overlapping_buffer->timestamp());
120
121  // TODO(dalecurtis): We should also clear |data| and |side_data|, but since
122  // that implies EOS care must be taken to ensure there are no clients relying
123  // on that behavior.
124
125  // Move over any preroll from this buffer.
126  if (preroll_buffer_) {
127    DCHECK(!overlapping_buffer->preroll_buffer_);
128    overlapping_buffer->preroll_buffer_.swap(preroll_buffer_);
129  }
130
131  // Rewrite |this| buffer as a splice buffer.
132  SetDecodeTimestamp(first_splice_buffer->GetDecodeTimestamp());
133  SetConfigId(first_splice_buffer->GetConfigId());
134  set_timestamp(first_splice_buffer->timestamp());
135  is_keyframe_ = first_splice_buffer->IsKeyframe();
136  type_ = first_splice_buffer->type();
137  track_id_ = first_splice_buffer->track_id();
138  set_splice_timestamp(overlapping_buffer->timestamp());
139
140  // The splice duration is the duration of all buffers before the splice plus
141  // the highest ending timestamp after the splice point.
142  set_duration(
143      std::max(overlapping_buffer->timestamp() + overlapping_buffer->duration(),
144               pre_splice_buffers.back()->timestamp() +
145                   pre_splice_buffers.back()->duration()) -
146      first_splice_buffer->timestamp());
147
148  // Copy all pre splice buffers into our wrapper buffer.
149  for (BufferQueue::const_iterator it = pre_splice_buffers.begin();
150       it != pre_splice_buffers.end();
151       ++it) {
152    const scoped_refptr<StreamParserBuffer>& buffer = *it;
153    DCHECK(!buffer->end_of_stream());
154    DCHECK(!buffer->preroll_buffer());
155    DCHECK(buffer->splice_buffers().empty());
156    splice_buffers_.push_back(CopyBuffer(*buffer));
157    splice_buffers_.back()->set_splice_timestamp(splice_timestamp());
158  }
159
160  splice_buffers_.push_back(overlapping_buffer);
161}
162
163void StreamParserBuffer::SetPrerollBuffer(
164    const scoped_refptr<StreamParserBuffer>& preroll_buffer) {
165  DCHECK(!preroll_buffer_);
166  DCHECK(!end_of_stream());
167  DCHECK(!preroll_buffer->end_of_stream());
168  DCHECK(!preroll_buffer->preroll_buffer_);
169  DCHECK(preroll_buffer->splice_timestamp() == kNoTimestamp());
170  DCHECK(preroll_buffer->splice_buffers().empty());
171  DCHECK(preroll_buffer->timestamp() <= timestamp());
172  DCHECK(preroll_buffer->discard_padding() == DecoderBuffer::DiscardPadding());
173  DCHECK_EQ(preroll_buffer->type(), type());
174  DCHECK_EQ(preroll_buffer->track_id(), track_id());
175
176  preroll_buffer_ = preroll_buffer;
177  preroll_buffer_->set_timestamp(timestamp());
178  preroll_buffer_->SetDecodeTimestamp(GetDecodeTimestamp());
179
180  // Mark the entire buffer for discard.
181  preroll_buffer_->set_discard_padding(
182      std::make_pair(kInfiniteDuration(), base::TimeDelta()));
183}
184
185void StreamParserBuffer::set_timestamp(base::TimeDelta timestamp) {
186  DecoderBuffer::set_timestamp(timestamp);
187  if (preroll_buffer_)
188    preroll_buffer_->set_timestamp(timestamp);
189}
190
191}  // namespace media
192