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 10 namespace media { 11 12 static 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 42 scoped_refptr<StreamParserBuffer> StreamParserBuffer::CreateEOSBuffer() { 43 return make_scoped_refptr(new StreamParserBuffer(NULL, 0, NULL, 0, false, 44 DemuxerStream::UNKNOWN, 0)); 45 } 46 47 scoped_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 55 scoped_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 64 DecodeTimestamp StreamParserBuffer::GetDecodeTimestamp() const { 65 if (decode_timestamp_ == kNoDecodeTimestamp()) 66 return DecodeTimestamp::FromPresentationTime(timestamp()); 67 return decode_timestamp_; 68 } 69 70 void StreamParserBuffer::SetDecodeTimestamp(DecodeTimestamp timestamp) { 71 decode_timestamp_ = timestamp; 72 if (preroll_buffer_.get()) 73 preroll_buffer_->SetDecodeTimestamp(timestamp); 74 } 75 76 StreamParserBuffer::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_(kNoDecodeTimestamp()), 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 94 StreamParserBuffer::~StreamParserBuffer() {} 95 96 int StreamParserBuffer::GetConfigId() const { 97 return config_id_; 98 } 99 100 void StreamParserBuffer::SetConfigId(int config_id) { 101 config_id_ = config_id; 102 if (preroll_buffer_.get()) 103 preroll_buffer_->SetConfigId(config_id); 104 } 105 106 int StreamParserBuffer::GetSpliceBufferConfigId(size_t index) const { 107 return index < splice_buffers().size() 108 ? splice_buffers_[index]->GetConfigId() 109 : GetConfigId(); 110 } 111 112 void StreamParserBuffer::ConvertToSpliceBuffer( 113 const BufferQueue& pre_splice_buffers) { 114 DCHECK(splice_buffers_.empty()); 115 DCHECK(duration() > base::TimeDelta()) 116 << "Only buffers with a valid duration can convert to a splice buffer." 117 << " pts " << timestamp().InSecondsF() 118 << " dts " << GetDecodeTimestamp().InSecondsF() 119 << " dur " << duration().InSecondsF(); 120 DCHECK(!end_of_stream()); 121 122 // Make a copy of this first, before making any changes. 123 scoped_refptr<StreamParserBuffer> overlapping_buffer = CopyBuffer(*this); 124 overlapping_buffer->set_splice_timestamp(kNoTimestamp()); 125 126 const scoped_refptr<StreamParserBuffer>& first_splice_buffer = 127 pre_splice_buffers.front(); 128 129 // Ensure the given buffers are actually before the splice point. 130 DCHECK(first_splice_buffer->timestamp() <= overlapping_buffer->timestamp()); 131 132 // TODO(dalecurtis): We should also clear |data| and |side_data|, but since 133 // that implies EOS care must be taken to ensure there are no clients relying 134 // on that behavior. 135 136 // Move over any preroll from this buffer. 137 if (preroll_buffer_.get()) { 138 DCHECK(!overlapping_buffer->preroll_buffer_.get()); 139 overlapping_buffer->preroll_buffer_.swap(preroll_buffer_); 140 } 141 142 // Rewrite |this| buffer as a splice buffer. 143 SetDecodeTimestamp(first_splice_buffer->GetDecodeTimestamp()); 144 SetConfigId(first_splice_buffer->GetConfigId()); 145 set_timestamp(first_splice_buffer->timestamp()); 146 is_keyframe_ = first_splice_buffer->IsKeyframe(); 147 type_ = first_splice_buffer->type(); 148 track_id_ = first_splice_buffer->track_id(); 149 set_splice_timestamp(overlapping_buffer->timestamp()); 150 151 // The splice duration is the duration of all buffers before the splice plus 152 // the highest ending timestamp after the splice point. 153 DCHECK(overlapping_buffer->duration() > base::TimeDelta()); 154 DCHECK(pre_splice_buffers.back()->duration() > base::TimeDelta()); 155 set_duration( 156 std::max(overlapping_buffer->timestamp() + overlapping_buffer->duration(), 157 pre_splice_buffers.back()->timestamp() + 158 pre_splice_buffers.back()->duration()) - 159 first_splice_buffer->timestamp()); 160 161 // Copy all pre splice buffers into our wrapper buffer. 162 for (BufferQueue::const_iterator it = pre_splice_buffers.begin(); 163 it != pre_splice_buffers.end(); 164 ++it) { 165 const scoped_refptr<StreamParserBuffer>& buffer = *it; 166 DCHECK(!buffer->end_of_stream()); 167 DCHECK(!buffer->preroll_buffer().get()); 168 DCHECK(buffer->splice_buffers().empty()); 169 splice_buffers_.push_back(CopyBuffer(*buffer.get())); 170 splice_buffers_.back()->set_splice_timestamp(splice_timestamp()); 171 } 172 173 splice_buffers_.push_back(overlapping_buffer); 174 } 175 176 void StreamParserBuffer::SetPrerollBuffer( 177 const scoped_refptr<StreamParserBuffer>& preroll_buffer) { 178 DCHECK(!preroll_buffer_.get()); 179 DCHECK(!end_of_stream()); 180 DCHECK(!preroll_buffer->end_of_stream()); 181 DCHECK(!preroll_buffer->preroll_buffer_.get()); 182 DCHECK(preroll_buffer->splice_timestamp() == kNoTimestamp()); 183 DCHECK(preroll_buffer->splice_buffers().empty()); 184 DCHECK(preroll_buffer->timestamp() <= timestamp()); 185 DCHECK(preroll_buffer->discard_padding() == DecoderBuffer::DiscardPadding()); 186 DCHECK_EQ(preroll_buffer->type(), type()); 187 DCHECK_EQ(preroll_buffer->track_id(), track_id()); 188 189 preroll_buffer_ = preroll_buffer; 190 preroll_buffer_->set_timestamp(timestamp()); 191 preroll_buffer_->SetDecodeTimestamp(GetDecodeTimestamp()); 192 193 // Mark the entire buffer for discard. 194 preroll_buffer_->set_discard_padding( 195 std::make_pair(kInfiniteDuration(), base::TimeDelta())); 196 } 197 198 void StreamParserBuffer::set_timestamp(base::TimeDelta timestamp) { 199 DecoderBuffer::set_timestamp(timestamp); 200 if (preroll_buffer_.get()) 201 preroll_buffer_->set_timestamp(timestamp); 202 } 203 204 } // namespace media 205