• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
EsAdapterVideo(const NewVideoConfigCB & new_video_config_cb,const EmitBufferCB & emit_buffer_cb)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 
~EsAdapterVideo()39 EsAdapterVideo::~EsAdapterVideo() {
40 }
41 
Flush()42 void EsAdapterVideo::Flush() {
43   ProcessPendingBuffers(true);
44 }
45 
Reset()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 
OnConfigChanged(const VideoDecoderConfig & video_decoder_config)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 
OnNewBuffer(const scoped_refptr<StreamParserBuffer> & stream_parser_buffer)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 
ProcessPendingBuffers(bool flush)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 
GetNextFramePts(base::TimeDelta current_pts)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 
ReplaceDiscardedFrames(const scoped_refptr<StreamParserBuffer> & stream_parser_buffer)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