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.
5 #include "media/formats/mp2t/es_adapter_video.h"
7 #include "media/base/buffers.h"
8 #include "media/base/video_decoder_config.h"
9 #include "media/formats/mp2t/mp2t_common.h"
14 // Arbitrary decision about the frame duration when there is no previous
15 // hint about what could be the frame duration.
16 static const int kDefaultFrameDurationMs
= 40;
18 // To calculate the frame duration, we make an assumption
19 // that the timestamp of the next frame in presentation order
20 // is no further than 5 frames away in decode order.
21 // TODO(damienv): the previous assumption should cover most of the practical
22 // cases. However, the right way to calculate the frame duration would be
23 // to emulate the H264 dpb bumping process.
24 static const size_t kHistorySize
= 5;
26 EsAdapterVideo::EsAdapterVideo(
27 const NewVideoConfigCB
& new_video_config_cb
,
28 const EmitBufferCB
& emit_buffer_cb
)
29 : new_video_config_cb_(new_video_config_cb
),
30 emit_buffer_cb_(emit_buffer_cb
),
31 has_valid_config_(false),
32 has_valid_frame_(false),
34 base::TimeDelta::FromMilliseconds(kDefaultFrameDurationMs
)),
36 has_valid_initial_timestamp_(false),
37 discarded_frame_count_(0) {
40 EsAdapterVideo::~EsAdapterVideo() {
43 void EsAdapterVideo::Flush() {
44 ProcessPendingBuffers(true);
47 void EsAdapterVideo::Reset() {
48 has_valid_config_
= false;
49 has_valid_frame_
= false;
51 last_frame_duration_
=
52 base::TimeDelta::FromMilliseconds(kDefaultFrameDurationMs
);
59 has_valid_initial_timestamp_
= false;
60 min_pts_
= base::TimeDelta();
61 min_dts_
= DecodeTimestamp();
63 discarded_frame_count_
= 0;
66 void EsAdapterVideo::OnConfigChanged(
67 const VideoDecoderConfig
& video_decoder_config
) {
68 config_list_
.push_back(
69 ConfigEntry(buffer_index_
+ buffer_list_
.size(), video_decoder_config
));
70 has_valid_config_
= true;
71 ProcessPendingBuffers(false);
74 bool EsAdapterVideo::OnNewBuffer(
75 const scoped_refptr
<StreamParserBuffer
>& stream_parser_buffer
) {
76 if (stream_parser_buffer
->timestamp() == kNoTimestamp()) {
77 if (has_valid_frame_
) {
78 // There is currently no error concealment for a missing timestamp
79 // in the middle of the stream.
80 DVLOG(1) << "Missing timestamp in the middle of the stream";
84 if (!has_valid_initial_timestamp_
) {
85 // MPEG-2 TS requires the first access unit to be given a timestamp.
86 // However, some streams do not comply with this requirement.
87 // So simply drop the frame if it is a leading frame with no timestamp.
89 << "Stream not compliant: ignoring leading frame with no timestamp";
93 // In all the other cases, this frame will be replaced by the following
94 // valid key frame, using timestamp interpolation.
95 DCHECK(has_valid_initial_timestamp_
);
96 DCHECK_GE(discarded_frame_count_
, 1);
97 discarded_frame_count_
++;
101 // At this point, timestamps of the incoming frame are valid.
102 if (!has_valid_initial_timestamp_
) {
103 min_pts_
= stream_parser_buffer
->timestamp();
104 min_dts_
= stream_parser_buffer
->GetDecodeTimestamp();
105 has_valid_initial_timestamp_
= true;
107 if (stream_parser_buffer
->timestamp() < min_pts_
)
108 min_pts_
= stream_parser_buffer
->timestamp();
110 // Discard the incoming frame:
111 // - if it is not associated with any config,
112 // - or if no valid key frame has been found so far.
113 if (!has_valid_config_
||
114 (!has_valid_frame_
&& !stream_parser_buffer
->is_key_frame())) {
115 discarded_frame_count_
++;
119 has_valid_frame_
= true;
121 if (discarded_frame_count_
> 0)
122 ReplaceDiscardedFrames(stream_parser_buffer
);
124 buffer_list_
.push_back(stream_parser_buffer
);
125 ProcessPendingBuffers(false);
129 void EsAdapterVideo::ProcessPendingBuffers(bool flush
) {
130 DCHECK(has_valid_config_
);
132 while (!buffer_list_
.empty() &&
133 (flush
|| buffer_list_
.size() > kHistorySize
)) {
134 // Signal a config change, just before emitting the corresponding frame.
135 if (!config_list_
.empty() && config_list_
.front().first
== buffer_index_
) {
136 new_video_config_cb_
.Run(config_list_
.front().second
);
137 config_list_
.pop_front();
140 scoped_refptr
<StreamParserBuffer
> buffer
= buffer_list_
.front();
141 buffer_list_
.pop_front();
144 if (buffer
->duration() == kNoTimestamp()) {
145 base::TimeDelta next_frame_pts
= GetNextFramePts(buffer
->timestamp());
146 if (next_frame_pts
== kNoTimestamp()) {
147 // This can happen when emitting the very last buffer
148 // or if the stream do not meet the assumption behind |kHistorySize|.
149 DVLOG(LOG_LEVEL_ES
) << "Using last frame duration: "
150 << last_frame_duration_
.InMilliseconds();
151 buffer
->set_duration(last_frame_duration_
);
153 base::TimeDelta duration
= next_frame_pts
- buffer
->timestamp();
154 DVLOG(LOG_LEVEL_ES
) << "Frame duration: " << duration
.InMilliseconds();
155 buffer
->set_duration(duration
);
159 emitted_pts_
.push_back(buffer
->timestamp());
160 if (emitted_pts_
.size() > kHistorySize
)
161 emitted_pts_
.pop_front();
163 last_frame_duration_
= buffer
->duration();
164 emit_buffer_cb_
.Run(buffer
);
168 base::TimeDelta
EsAdapterVideo::GetNextFramePts(base::TimeDelta current_pts
) {
169 base::TimeDelta next_pts
= kNoTimestamp();
171 // Consider the timestamps of future frames (in decode order).
172 // Note: the next frame is not enough when the GOP includes some B frames.
173 for (BufferQueue::const_iterator it
= buffer_list_
.begin();
174 it
!= buffer_list_
.end(); ++it
) {
175 if ((*it
)->timestamp() < current_pts
)
177 if (next_pts
== kNoTimestamp() || next_pts
> (*it
)->timestamp())
178 next_pts
= (*it
)->timestamp();
181 // Consider the timestamps of previous frames (in decode order).
182 // In a simple GOP structure with B frames, the frame next to the last B
183 // frame (in presentation order) is located before in decode order.
184 for (std::list
<base::TimeDelta
>::const_iterator it
= emitted_pts_
.begin();
185 it
!= emitted_pts_
.end(); ++it
) {
186 if (*it
< current_pts
)
188 if (next_pts
== kNoTimestamp() || next_pts
> *it
)
195 void EsAdapterVideo::ReplaceDiscardedFrames(
196 const scoped_refptr
<StreamParserBuffer
>& stream_parser_buffer
) {
197 DCHECK_GT(discarded_frame_count_
, 0);
198 DCHECK(stream_parser_buffer
->is_key_frame());
200 // PTS/DTS are interpolated between the min PTS/DTS of discarded frames
201 // and the PTS/DTS of the first valid buffer.
202 // Note: |pts_delta| and |dts_delta| are calculated using integer division.
203 // Interpolation thus accumulutes small errors. However, since timestamps
204 // are given in microseconds, only a high number of discarded frames
205 // (in the order of 10000s) could have an impact and create a gap (from MSE
206 // point of view) between the last interpolated frame and
207 // |stream_parser_buffer|.
208 base::TimeDelta pts
= min_pts_
;
209 base::TimeDelta pts_delta
=
210 (stream_parser_buffer
->timestamp() - pts
) / discarded_frame_count_
;
211 DecodeTimestamp dts
= min_dts_
;
212 base::TimeDelta dts_delta
=
213 (stream_parser_buffer
->GetDecodeTimestamp() - dts
) /
214 discarded_frame_count_
;
216 for (int i
= 0; i
< discarded_frame_count_
; i
++) {
217 scoped_refptr
<StreamParserBuffer
> frame
=
218 StreamParserBuffer::CopyFrom(
219 stream_parser_buffer
->data(),
220 stream_parser_buffer
->data_size(),
221 stream_parser_buffer
->is_key_frame(),
222 stream_parser_buffer
->type(),
223 stream_parser_buffer
->track_id());
224 frame
->SetDecodeTimestamp(dts
);
225 frame
->set_timestamp(pts
);
226 frame
->set_duration(pts_delta
);
227 buffer_list_
.push_back(frame
);
231 discarded_frame_count_
= 0;