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 12namespace media { 13namespace mp2t { 14 15// Arbitrary decision about the frame duration when there is no previous 16// hint about what could be the frame duration. 17static 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. 25static const size_t kHistorySize = 5; 26 27EsAdapterVideo::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 39EsAdapterVideo::~EsAdapterVideo() { 40} 41 42void EsAdapterVideo::Flush() { 43 ProcessPendingBuffers(true); 44} 45 46void 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 62void 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 70void 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 95void 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 134base::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 161void 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