1 // Copyright 2014 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/formats/mp2t/es_adapter_video.h" 6 7 #include "media/base/buffers.h" 8 #include "media/base/stream_parser_buffer.h" 9 #include "media/base/video_decoder_config.h" 10 #include "media/formats/mp2t/mp2t_common.h" 11 12 namespace media { 13 namespace mp2t { 14 15 // Arbitrary decision about the frame duration when there is no previous 16 // hint about what could be the frame duration. 17 static const int kDefaultFrameDurationMs = 40; 18 19 // To calculate the frame duration, we make an assumption 20 // that the timestamp of the next frame in presentation order 21 // is no further than 5 frames away in decode order. 22 // TODO(damienv): the previous assumption should cover most of the practical 23 // cases. However, the right way to calculate the frame duration would be 24 // to emulate the H264 dpb bumping process. 25 static const size_t kHistorySize = 5; 26 27 EsAdapterVideo::EsAdapterVideo( 28 const NewVideoConfigCB& new_video_config_cb, 29 const EmitBufferCB& emit_buffer_cb) 30 : new_video_config_cb_(new_video_config_cb), 31 emit_buffer_cb_(emit_buffer_cb), 32 has_valid_config_(false), 33 has_valid_frame_(false), 34 last_frame_duration_( 35 base::TimeDelta::FromMilliseconds(kDefaultFrameDurationMs)), 36 buffer_index_(0) { 37 } 38 39 EsAdapterVideo::~EsAdapterVideo() { 40 } 41 42 void EsAdapterVideo::Flush() { 43 ProcessPendingBuffers(true); 44 } 45 46 void EsAdapterVideo::Reset() { 47 has_valid_config_ = false; 48 has_valid_frame_ = false; 49 50 last_frame_duration_ = 51 base::TimeDelta::FromMilliseconds(kDefaultFrameDurationMs); 52 53 config_list_.clear(); 54 buffer_index_ = 0; 55 buffer_list_.clear(); 56 emitted_pts_.clear(); 57 58 discarded_frames_min_pts_ = base::TimeDelta(); 59 discarded_frames_dts_.clear(); 60 } 61 62 void EsAdapterVideo::OnConfigChanged( 63 const VideoDecoderConfig& video_decoder_config) { 64 config_list_.push_back( 65 ConfigEntry(buffer_index_ + buffer_list_.size(), video_decoder_config)); 66 has_valid_config_ = true; 67 ProcessPendingBuffers(false); 68 } 69 70 void EsAdapterVideo::OnNewBuffer( 71 const scoped_refptr<StreamParserBuffer>& stream_parser_buffer) { 72 // Discard the incoming frame: 73 // - if it is not associated with any config, 74 // - or if only non-key frames have been added to a new segment. 75 if (!has_valid_config_ || 76 (!has_valid_frame_ && !stream_parser_buffer->IsKeyframe())) { 77 if (discarded_frames_dts_.empty() || 78 discarded_frames_min_pts_ > stream_parser_buffer->timestamp()) { 79 discarded_frames_min_pts_ = stream_parser_buffer->timestamp(); 80 } 81 discarded_frames_dts_.push_back( 82 stream_parser_buffer->GetDecodeTimestamp()); 83 return; 84 } 85 86 has_valid_frame_ = true; 87 88 if (!discarded_frames_dts_.empty()) 89 ReplaceDiscardedFrames(stream_parser_buffer); 90 91 buffer_list_.push_back(stream_parser_buffer); 92 ProcessPendingBuffers(false); 93 } 94 95 void EsAdapterVideo::ProcessPendingBuffers(bool flush) { 96 DCHECK(has_valid_config_); 97 98 while (!buffer_list_.empty() && 99 (flush || buffer_list_.size() > kHistorySize)) { 100 // Signal a config change, just before emitting the corresponding frame. 101 if (!config_list_.empty() && config_list_.front().first == buffer_index_) { 102 new_video_config_cb_.Run(config_list_.front().second); 103 config_list_.pop_front(); 104 } 105 106 scoped_refptr<StreamParserBuffer> buffer = buffer_list_.front(); 107 buffer_list_.pop_front(); 108 buffer_index_++; 109 110 if (buffer->duration() == kNoTimestamp()) { 111 base::TimeDelta next_frame_pts = GetNextFramePts(buffer->timestamp()); 112 if (next_frame_pts == kNoTimestamp()) { 113 // This can happen when emitting the very last buffer 114 // or if the stream do not meet the assumption behind |kHistorySize|. 115 DVLOG(LOG_LEVEL_ES) << "Using last frame duration: " 116 << last_frame_duration_.InMilliseconds(); 117 buffer->set_duration(last_frame_duration_); 118 } else { 119 base::TimeDelta duration = next_frame_pts - buffer->timestamp(); 120 DVLOG(LOG_LEVEL_ES) << "Frame duration: " << duration.InMilliseconds(); 121 buffer->set_duration(duration); 122 } 123 } 124 125 emitted_pts_.push_back(buffer->timestamp()); 126 if (emitted_pts_.size() > kHistorySize) 127 emitted_pts_.pop_front(); 128 129 last_frame_duration_ = buffer->duration(); 130 emit_buffer_cb_.Run(buffer); 131 } 132 } 133 134 base::TimeDelta EsAdapterVideo::GetNextFramePts(base::TimeDelta current_pts) { 135 base::TimeDelta next_pts = kNoTimestamp(); 136 137 // Consider the timestamps of future frames (in decode order). 138 // Note: the next frame is not enough when the GOP includes some B frames. 139 for (BufferQueue::const_iterator it = buffer_list_.begin(); 140 it != buffer_list_.end(); ++it) { 141 if ((*it)->timestamp() < current_pts) 142 continue; 143 if (next_pts == kNoTimestamp() || next_pts > (*it)->timestamp()) 144 next_pts = (*it)->timestamp(); 145 } 146 147 // Consider the timestamps of previous frames (in decode order). 148 // In a simple GOP structure with B frames, the frame next to the last B 149 // frame (in presentation order) is located before in decode order. 150 for (std::list<base::TimeDelta>::const_iterator it = emitted_pts_.begin(); 151 it != emitted_pts_.end(); ++it) { 152 if (*it < current_pts) 153 continue; 154 if (next_pts == kNoTimestamp() || next_pts > *it) 155 next_pts = *it; 156 } 157 158 return next_pts; 159 } 160 161 void EsAdapterVideo::ReplaceDiscardedFrames( 162 const scoped_refptr<StreamParserBuffer>& stream_parser_buffer) { 163 DCHECK(!discarded_frames_dts_.empty()); 164 DCHECK(stream_parser_buffer->IsKeyframe()); 165 166 // PTS is interpolated between the min PTS of discarded frames 167 // and the PTS of the first valid buffer. 168 base::TimeDelta pts = discarded_frames_min_pts_; 169 base::TimeDelta pts_delta = 170 (stream_parser_buffer->timestamp() - pts) / discarded_frames_dts_.size(); 171 172 while (!discarded_frames_dts_.empty()) { 173 scoped_refptr<StreamParserBuffer> frame = 174 StreamParserBuffer::CopyFrom( 175 stream_parser_buffer->data(), 176 stream_parser_buffer->data_size(), 177 stream_parser_buffer->IsKeyframe(), 178 stream_parser_buffer->type(), 179 stream_parser_buffer->track_id()); 180 frame->SetDecodeTimestamp(discarded_frames_dts_.front()); 181 frame->set_timestamp(pts); 182 frame->set_duration(pts_delta); 183 buffer_list_.push_back(frame); 184 pts += pts_delta; 185 discarded_frames_dts_.pop_front(); 186 } 187 } 188 189 } // namespace mp2t 190 } // namespace media 191