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 <stddef.h>
6 #include <stdint.h>
7
8 #include <map>
9 #include <memory>
10 #include <string>
11 #include <vector>
12
13 #include "base/bind.h"
14 #include "base/macros.h"
15 #include "base/run_loop.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_split.h"
18 #include "base/strings/string_util.h"
19 #include "base/test/task_environment.h"
20 #include "base/time/time.h"
21 #include "media/base/media_log.h"
22 #include "media/base/media_util.h"
23 #include "media/base/mock_filters.h"
24 #include "media/base/mock_media_log.h"
25 #include "media/base/test_helpers.h"
26 #include "media/base/timestamp_constants.h"
27 #include "media/filters/chunk_demuxer.h"
28 #include "media/filters/frame_processor.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30
31 using ::testing::_;
32 using ::testing::InSequence;
33 using ::testing::StrictMock;
34 using ::testing::Values;
35
36 namespace {
37
38 // Helper to shorten "base::TimeDelta::FromMilliseconds(...)" in these test
39 // cases for integer milliseconds.
Milliseconds(int64_t milliseconds)40 constexpr base::TimeDelta Milliseconds(int64_t milliseconds) {
41 return base::TimeDelta::FromMilliseconds(milliseconds);
42 }
43
44 } // namespace
45
46 namespace media {
47
48 typedef StreamParser::BufferQueue BufferQueue;
49 typedef StreamParser::TrackId TrackId;
50
51 // Used for setting expectations on callbacks. Using a StrictMock also lets us
52 // test for missing or extra callbacks.
53 class FrameProcessorTestCallbackHelper {
54 public:
55 FrameProcessorTestCallbackHelper() = default;
56 virtual ~FrameProcessorTestCallbackHelper() = default;
57
58 MOCK_METHOD1(OnParseWarning, void(const SourceBufferParseWarning));
59 MOCK_METHOD1(PossibleDurationIncrease, void(base::TimeDelta new_duration));
60
61 // Helper that calls the mock method as well as does basic sanity checks on
62 // |new_duration|.
OnPossibleDurationIncrease(base::TimeDelta new_duration)63 void OnPossibleDurationIncrease(base::TimeDelta new_duration) {
64 PossibleDurationIncrease(new_duration);
65 ASSERT_NE(kNoTimestamp, new_duration);
66 ASSERT_NE(kInfiniteDuration, new_duration);
67 }
68
69 MOCK_METHOD2(OnAppend,
70 void(const DemuxerStream::Type type,
71 const BufferQueue* buffers));
72 MOCK_METHOD3(OnGroupStart,
73 void(const DemuxerStream::Type type,
74 DecodeTimestamp start_dts,
75 base::TimeDelta start_pts));
76
77 private:
78 DISALLOW_COPY_AND_ASSIGN(FrameProcessorTestCallbackHelper);
79 };
80
81 class FrameProcessorTest : public ::testing::TestWithParam<bool> {
82 protected:
FrameProcessorTest()83 FrameProcessorTest()
84 : append_window_end_(kInfiniteDuration),
85 frame_duration_(Milliseconds(10)),
86 audio_id_(1),
87 video_id_(2) {
88 use_sequence_mode_ = GetParam();
89 frame_processor_ = std::make_unique<FrameProcessor>(
90 base::BindRepeating(
91 &FrameProcessorTestCallbackHelper::OnPossibleDurationIncrease,
92 base::Unretained(&callbacks_)),
93 &media_log_);
94 frame_processor_->SetParseWarningCallback(
95 base::BindRepeating(&FrameProcessorTestCallbackHelper::OnParseWarning,
96 base::Unretained(&callbacks_)));
97 }
98
99 enum StreamFlags {
100 HAS_AUDIO = 1 << 0,
101 HAS_VIDEO = 1 << 1,
102 OBSERVE_APPENDS_AND_GROUP_STARTS = 1 << 2,
103 USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES = 1 << 3
104 };
105
AddTestTracks(int stream_flags)106 void AddTestTracks(int stream_flags) {
107 const bool has_audio = (stream_flags & HAS_AUDIO) != 0;
108 const bool has_video = (stream_flags & HAS_VIDEO) != 0;
109 ASSERT_TRUE(has_audio || has_video);
110
111 const bool setup_observers =
112 (stream_flags & OBSERVE_APPENDS_AND_GROUP_STARTS) != 0;
113
114 const bool support_audio_nonkeyframes =
115 (stream_flags & USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES) != 0;
116 ASSERT_TRUE(has_audio || !support_audio_nonkeyframes);
117
118 if (has_audio) {
119 CreateAndConfigureStream(DemuxerStream::AUDIO, setup_observers,
120 support_audio_nonkeyframes);
121 ASSERT_TRUE(audio_);
122 EXPECT_TRUE(frame_processor_->AddTrack(audio_id_, audio_.get()));
123 SeekStream(audio_.get(), Milliseconds(0));
124 }
125 if (has_video) {
126 CreateAndConfigureStream(DemuxerStream::VIDEO, setup_observers, false);
127 ASSERT_TRUE(video_);
128 EXPECT_TRUE(frame_processor_->AddTrack(video_id_, video_.get()));
129 SeekStream(video_.get(), Milliseconds(0));
130 }
131 }
132
SetTimestampOffset(base::TimeDelta new_offset)133 void SetTimestampOffset(base::TimeDelta new_offset) {
134 timestamp_offset_ = new_offset;
135 frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset_);
136 }
137
StringToBufferQueue(const std::string & buffers_to_append,const TrackId track_id,const DemuxerStream::Type type)138 BufferQueue StringToBufferQueue(const std::string& buffers_to_append,
139 const TrackId track_id,
140 const DemuxerStream::Type type) {
141 std::vector<std::string> timestamps = base::SplitString(
142 buffers_to_append, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
143
144 BufferQueue buffers;
145 for (size_t i = 0; i < timestamps.size(); i++) {
146 bool is_keyframe = false;
147 if (base::EndsWith(timestamps[i], "K", base::CompareCase::SENSITIVE)) {
148 is_keyframe = true;
149 // Remove the "K" off of the token.
150 timestamps[i] = timestamps[i].substr(0, timestamps[i].length() - 1);
151 }
152
153 // Use custom decode timestamp if included.
154 std::vector<std::string> buffer_timestamps = base::SplitString(
155 timestamps[i], "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
156 if (buffer_timestamps.size() == 1)
157 buffer_timestamps.push_back(buffer_timestamps[0]);
158 CHECK_EQ(2u, buffer_timestamps.size());
159
160 double time_in_ms, decode_time_in_ms;
161 CHECK(base::StringToDouble(buffer_timestamps[0], &time_in_ms));
162 CHECK(base::StringToDouble(buffer_timestamps[1], &decode_time_in_ms));
163
164 // Create buffer. Encode the original time_in_ms as the buffer's data to
165 // enable later verification of possible buffer relocation in presentation
166 // timeline due to coded frame processing.
167 const uint8_t* timestamp_as_data =
168 reinterpret_cast<uint8_t*>(&time_in_ms);
169 scoped_refptr<StreamParserBuffer> buffer =
170 StreamParserBuffer::CopyFrom(timestamp_as_data, sizeof(time_in_ms),
171 is_keyframe, type, track_id);
172 buffer->set_timestamp(base::TimeDelta::FromMillisecondsD(time_in_ms));
173 if (time_in_ms != decode_time_in_ms) {
174 buffer->SetDecodeTimestamp(DecodeTimestamp::FromPresentationTime(
175 base::TimeDelta::FromMillisecondsD(decode_time_in_ms)));
176 }
177
178 buffer->set_duration(frame_duration_);
179 buffers.push_back(buffer);
180 }
181 return buffers;
182 }
183
ProcessFrames(const std::string & audio_timestamps,const std::string & video_timestamps)184 bool ProcessFrames(const std::string& audio_timestamps,
185 const std::string& video_timestamps) {
186 StreamParser::BufferQueueMap buffer_queue_map;
187 const auto& audio_buffers =
188 StringToBufferQueue(audio_timestamps, audio_id_, DemuxerStream::AUDIO);
189 if (!audio_buffers.empty())
190 buffer_queue_map.insert(std::make_pair(audio_id_, audio_buffers));
191 const auto& video_buffers =
192 StringToBufferQueue(video_timestamps, video_id_, DemuxerStream::VIDEO);
193 if (!video_buffers.empty())
194 buffer_queue_map.insert(std::make_pair(video_id_, video_buffers));
195 return frame_processor_->ProcessFrames(
196 buffer_queue_map, append_window_start_, append_window_end_,
197 ×tamp_offset_);
198 }
199
200 // Compares |expected| to the buffered ranges of |stream| formatted into a
201 // string as follows:
202 //
203 // If no ranges: "{ }"
204 // If one range: "{ [start1,end1) }"
205 // If multiple ranges, they are added space-delimited in sequence, like:
206 // "{ [start1,end1) [start2,end2) }"
207 //
208 // startN and endN are the respective buffered start and end times of the
209 // range in integer milliseconds.
CheckExpectedRangesByTimestamp(ChunkDemuxerStream * stream,const std::string & expected)210 void CheckExpectedRangesByTimestamp(ChunkDemuxerStream* stream,
211 const std::string& expected) {
212 // Note, DemuxerStream::TEXT streams return [0,duration (==infinity here))
213 Ranges<base::TimeDelta> r = stream->GetBufferedRanges(kInfiniteDuration);
214
215 std::stringstream ss;
216 ss << "{ ";
217 for (size_t i = 0; i < r.size(); ++i) {
218 int64_t start = r.start(i).InMilliseconds();
219 int64_t end = r.end(i).InMilliseconds();
220 ss << "[" << start << "," << end << ") ";
221 }
222 ss << "}";
223 EXPECT_EQ(expected, ss.str());
224 }
225
CheckReadStalls(ChunkDemuxerStream * stream)226 void CheckReadStalls(ChunkDemuxerStream* stream) {
227 int loop_count = 0;
228
229 do {
230 read_callback_called_ = false;
231 stream->Read(base::BindOnce(&FrameProcessorTest::StoreStatusAndBuffer,
232 base::Unretained(this)));
233 base::RunLoop().RunUntilIdle();
234 } while (++loop_count < 2 && read_callback_called_ &&
235 last_read_status_ == DemuxerStream::kAborted);
236
237 ASSERT_FALSE(read_callback_called_ &&
238 last_read_status_ == DemuxerStream::kAborted)
239 << "2 kAborted reads in a row. Giving up.";
240 EXPECT_FALSE(read_callback_called_);
241 }
242
243 // Doesn't check keyframeness, but otherwise is the same as
244 // CheckReadsAndOptionallyKeyframenessThenReadStalls().
CheckReadsThenReadStalls(ChunkDemuxerStream * stream,const std::string & expected)245 void CheckReadsThenReadStalls(ChunkDemuxerStream* stream,
246 const std::string& expected) {
247 CheckReadsAndOptionallyKeyframenessThenReadStalls(stream, expected, false);
248 }
249
250 // Checks keyframeness using
251 // CheckReadsAndOptionallyKeyframenessThenReadStalls().
CheckReadsAndKeyframenessThenReadStalls(ChunkDemuxerStream * stream,const std::string & expected)252 void CheckReadsAndKeyframenessThenReadStalls(ChunkDemuxerStream* stream,
253 const std::string& expected) {
254 CheckReadsAndOptionallyKeyframenessThenReadStalls(stream, expected, true);
255 }
256
257 // Format of |expected| is a space-delimited sequence of
258 // timestamp_in_ms:original_timestamp_in_ms. original_timestamp_in_ms (and the
259 // colon) must be omitted if it is the same as timestamp_in_ms. If
260 // |check_keyframeness| is true, then each frame in |expected| must end with
261 // 'K' or 'N', which respectively must match the read result frames'
262 // keyframeness.
CheckReadsAndOptionallyKeyframenessThenReadStalls(ChunkDemuxerStream * stream,const std::string & expected,bool check_keyframeness)263 void CheckReadsAndOptionallyKeyframenessThenReadStalls(
264 ChunkDemuxerStream* stream,
265 const std::string& expected,
266 bool check_keyframeness) {
267 std::vector<std::string> timestamps = base::SplitString(
268 expected, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
269 std::stringstream ss;
270 for (size_t i = 0; i < timestamps.size(); ++i) {
271 int loop_count = 0;
272
273 do {
274 read_callback_called_ = false;
275 stream->Read(base::BindOnce(&FrameProcessorTest::StoreStatusAndBuffer,
276 base::Unretained(this)));
277 base::RunLoop().RunUntilIdle();
278 EXPECT_TRUE(read_callback_called_);
279 } while (++loop_count < 2 &&
280 last_read_status_ == DemuxerStream::kAborted);
281
282 ASSERT_FALSE(last_read_status_ == DemuxerStream::kAborted)
283 << "2 kAborted reads in a row. Giving up.";
284 EXPECT_EQ(DemuxerStream::kOk, last_read_status_);
285 EXPECT_FALSE(last_read_buffer_->end_of_stream());
286
287 if (i > 0)
288 ss << " ";
289
290 int time_in_ms = last_read_buffer_->timestamp().InMilliseconds();
291 ss << time_in_ms;
292
293 // Decode the original_time_in_ms from the buffer's data.
294 double original_time_in_ms;
295 ASSERT_EQ(sizeof(original_time_in_ms), last_read_buffer_->data_size());
296 original_time_in_ms = *(reinterpret_cast<const double*>(
297 last_read_buffer_->data()));
298 if (original_time_in_ms != time_in_ms)
299 ss << ":" << original_time_in_ms;
300
301 // Detect full-discard preroll buffer.
302 if (last_read_buffer_->discard_padding().first == kInfiniteDuration &&
303 last_read_buffer_->discard_padding().second.is_zero()) {
304 ss << "P";
305 }
306
307 // Conditionally check keyframeness.
308 if (check_keyframeness) {
309 if (last_read_buffer_->is_key_frame())
310 ss << "K";
311 else
312 ss << "N";
313 }
314 }
315
316 EXPECT_EQ(expected, ss.str());
317 CheckReadStalls(stream);
318 }
319
320 // TODO(wolenetz): Refactor to instead verify the expected signalling or lack
321 // thereof of new coded frame group by the FrameProcessor. See
322 // https://crbug.com/580613.
in_coded_frame_group()323 bool in_coded_frame_group() {
324 return !frame_processor_->pending_notify_all_group_start_;
325 }
326
SeekStream(ChunkDemuxerStream * stream,base::TimeDelta seek_time)327 void SeekStream(ChunkDemuxerStream* stream, base::TimeDelta seek_time) {
328 stream->AbortReads();
329 stream->Seek(seek_time);
330 stream->StartReturningData();
331 }
332
333 base::test::SingleThreadTaskEnvironment task_environment_;
334 StrictMock<MockMediaLog> media_log_;
335 StrictMock<FrameProcessorTestCallbackHelper> callbacks_;
336
337 bool use_sequence_mode_;
338
339 std::unique_ptr<FrameProcessor> frame_processor_;
340 base::TimeDelta append_window_start_;
341 base::TimeDelta append_window_end_;
342 base::TimeDelta timestamp_offset_;
343 base::TimeDelta frame_duration_;
344 std::unique_ptr<ChunkDemuxerStream> audio_;
345 std::unique_ptr<ChunkDemuxerStream> video_;
346 const TrackId audio_id_;
347 const TrackId video_id_;
348 const BufferQueue empty_queue_;
349
350 // StoreStatusAndBuffer's most recent result.
351 DemuxerStream::Status last_read_status_;
352 scoped_refptr<DecoderBuffer> last_read_buffer_;
353 bool read_callback_called_;
354
355 private:
StoreStatusAndBuffer(DemuxerStream::Status status,scoped_refptr<DecoderBuffer> buffer)356 void StoreStatusAndBuffer(DemuxerStream::Status status,
357 scoped_refptr<DecoderBuffer> buffer) {
358 if (status == DemuxerStream::kOk && buffer.get()) {
359 DVLOG(3) << __func__ << "status: " << status
360 << " ts: " << buffer->timestamp().InSecondsF();
361 } else {
362 DVLOG(3) << __func__ << "status: " << status << " ts: n/a";
363 }
364
365 read_callback_called_ = true;
366 last_read_status_ = status;
367 last_read_buffer_ = buffer;
368 }
369
CreateAndConfigureStream(DemuxerStream::Type type,bool setup_observers,bool support_audio_nonkeyframes)370 void CreateAndConfigureStream(DemuxerStream::Type type,
371 bool setup_observers,
372 bool support_audio_nonkeyframes) {
373 // TODO(wolenetz/dalecurtis): Also test with splicing disabled?
374
375 ChunkDemuxerStream* stream;
376 switch (type) {
377 case DemuxerStream::AUDIO: {
378 ASSERT_FALSE(audio_);
379 audio_ = std::make_unique<ChunkDemuxerStream>(DemuxerStream::AUDIO,
380 MediaTrack::Id("1"));
381 AudioDecoderConfig decoder_config;
382 if (support_audio_nonkeyframes) {
383 decoder_config = AudioDecoderConfig(
384 kCodecAAC, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 1000,
385 EmptyExtraData(), EncryptionScheme::kUnencrypted);
386 decoder_config.set_profile(AudioCodecProfile::kXHE_AAC);
387 } else {
388 decoder_config = AudioDecoderConfig(
389 kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 1000,
390 EmptyExtraData(), EncryptionScheme::kUnencrypted);
391 }
392 frame_processor_->OnPossibleAudioConfigUpdate(decoder_config);
393 ASSERT_TRUE(
394 audio_->UpdateAudioConfig(decoder_config, false, &media_log_));
395
396 stream = audio_.get();
397 break;
398 }
399 case DemuxerStream::VIDEO: {
400 ASSERT_FALSE(video_);
401 ASSERT_FALSE(support_audio_nonkeyframes);
402 video_ = std::make_unique<ChunkDemuxerStream>(DemuxerStream::VIDEO,
403 MediaTrack::Id("2"));
404 ASSERT_TRUE(video_->UpdateVideoConfig(TestVideoConfig::Normal(), false,
405 &media_log_));
406 stream = video_.get();
407 break;
408 }
409 // TODO(wolenetz): Test text coded frame processing.
410 case DemuxerStream::TEXT:
411 case DemuxerStream::UNKNOWN: {
412 ASSERT_FALSE(true);
413 }
414 }
415
416 if (setup_observers) {
417 stream->set_append_observer_for_testing(
418 base::BindRepeating(&FrameProcessorTestCallbackHelper::OnAppend,
419 base::Unretained(&callbacks_), type));
420 stream->set_group_start_observer_for_testing(
421 base::BindRepeating(&FrameProcessorTestCallbackHelper::OnGroupStart,
422 base::Unretained(&callbacks_), type));
423 }
424 }
425
426 DISALLOW_COPY_AND_ASSIGN(FrameProcessorTest);
427 };
428
TEST_P(FrameProcessorTest,WrongTypeInAppendedBuffer)429 TEST_P(FrameProcessorTest, WrongTypeInAppendedBuffer) {
430 AddTestTracks(HAS_AUDIO);
431 EXPECT_FALSE(in_coded_frame_group());
432
433 StreamParser::BufferQueueMap buffer_queue_map;
434 const auto& audio_buffers =
435 StringToBufferQueue("0K", audio_id_, DemuxerStream::VIDEO);
436 buffer_queue_map.insert(std::make_pair(audio_id_, audio_buffers));
437 EXPECT_MEDIA_LOG(FrameTypeMismatchesTrackType("video", "1"));
438 ASSERT_FALSE(
439 frame_processor_->ProcessFrames(buffer_queue_map, append_window_start_,
440 append_window_end_, ×tamp_offset_));
441 EXPECT_FALSE(in_coded_frame_group());
442 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
443 CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
444 CheckReadStalls(audio_.get());
445 }
446
TEST_P(FrameProcessorTest,NonMonotonicallyIncreasingTimestampInOneCall)447 TEST_P(FrameProcessorTest, NonMonotonicallyIncreasingTimestampInOneCall) {
448 AddTestTracks(HAS_AUDIO);
449
450 EXPECT_MEDIA_LOG(ParsedBuffersNotInDTSSequence());
451 EXPECT_FALSE(ProcessFrames("10K 0K", ""));
452 EXPECT_FALSE(in_coded_frame_group());
453 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
454 CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
455 CheckReadStalls(audio_.get());
456 }
457
TEST_P(FrameProcessorTest,AudioOnly_SingleFrame)458 TEST_P(FrameProcessorTest, AudioOnly_SingleFrame) {
459 // Tests A: P(A) -> (a)
460 InSequence s;
461 AddTestTracks(HAS_AUDIO);
462 if (use_sequence_mode_)
463 frame_processor_->SetSequenceMode(true);
464
465 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
466 EXPECT_TRUE(ProcessFrames("0K", ""));
467 EXPECT_TRUE(in_coded_frame_group());
468 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
469 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) }");
470 CheckReadsThenReadStalls(audio_.get(), "0");
471 }
472
TEST_P(FrameProcessorTest,VideoOnly_SingleFrame)473 TEST_P(FrameProcessorTest, VideoOnly_SingleFrame) {
474 // Tests V: P(V) -> (v)
475 InSequence s;
476 AddTestTracks(HAS_VIDEO);
477 if (use_sequence_mode_)
478 frame_processor_->SetSequenceMode(true);
479
480 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
481 EXPECT_TRUE(ProcessFrames("", "0K"));
482 EXPECT_TRUE(in_coded_frame_group());
483 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
484 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,10) }");
485 CheckReadsThenReadStalls(video_.get(), "0");
486 }
487
TEST_P(FrameProcessorTest,AudioOnly_TwoFrames)488 TEST_P(FrameProcessorTest, AudioOnly_TwoFrames) {
489 // Tests A: P(A0, A10) -> (a0, a10)
490 InSequence s;
491 AddTestTracks(HAS_AUDIO);
492 if (use_sequence_mode_)
493 frame_processor_->SetSequenceMode(true);
494
495 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
496 EXPECT_TRUE(ProcessFrames("0K 10K", ""));
497 EXPECT_TRUE(in_coded_frame_group());
498 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
499 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
500 CheckReadsThenReadStalls(audio_.get(), "0 10");
501 }
502
TEST_P(FrameProcessorTest,AudioOnly_SetOffsetThenSingleFrame)503 TEST_P(FrameProcessorTest, AudioOnly_SetOffsetThenSingleFrame) {
504 // Tests A: STSO(50)+P(A0) -> TSO==50,(a0@50)
505 InSequence s;
506 AddTestTracks(HAS_AUDIO);
507 if (use_sequence_mode_)
508 frame_processor_->SetSequenceMode(true);
509
510 SetTimestampOffset(Milliseconds(50));
511 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
512 EXPECT_TRUE(ProcessFrames("0K", ""));
513 EXPECT_TRUE(in_coded_frame_group());
514 EXPECT_EQ(Milliseconds(50), timestamp_offset_);
515 CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) }");
516
517 // We do not stall on reading without seeking to 50ms due to
518 // SourceBufferStream::kSeekToStartFudgeRoom().
519 CheckReadsThenReadStalls(audio_.get(), "50:0");
520 }
521
TEST_P(FrameProcessorTest,AudioOnly_SetOffsetThenFrameTimestampBelowOffset)522 TEST_P(FrameProcessorTest, AudioOnly_SetOffsetThenFrameTimestampBelowOffset) {
523 // Tests A: STSO(50)+P(A20) ->
524 // if sequence mode: TSO==30,(a20@50)
525 // if segments mode: TSO==50,(a20@70)
526 InSequence s;
527 AddTestTracks(HAS_AUDIO);
528 if (use_sequence_mode_)
529 frame_processor_->SetSequenceMode(true);
530
531 SetTimestampOffset(Milliseconds(50));
532
533 if (use_sequence_mode_) {
534 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
535 } else {
536 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(80)));
537 }
538
539 EXPECT_TRUE(ProcessFrames("20K", ""));
540 EXPECT_TRUE(in_coded_frame_group());
541
542 // We do not stall on reading without seeking to 50ms / 70ms due to
543 // SourceBufferStream::kSeekToStartFudgeRoom().
544 if (use_sequence_mode_) {
545 EXPECT_EQ(Milliseconds(30), timestamp_offset_);
546 CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) }");
547 CheckReadsThenReadStalls(audio_.get(), "50:20");
548 } else {
549 EXPECT_EQ(Milliseconds(50), timestamp_offset_);
550 CheckExpectedRangesByTimestamp(audio_.get(), "{ [70,80) }");
551 CheckReadsThenReadStalls(audio_.get(), "70:20");
552 }
553 }
554
TEST_P(FrameProcessorTest,AudioOnly_SequentialProcessFrames)555 TEST_P(FrameProcessorTest, AudioOnly_SequentialProcessFrames) {
556 // Tests A: P(A0,A10)+P(A20,A30) -> (a0,a10,a20,a30)
557 InSequence s;
558 AddTestTracks(HAS_AUDIO);
559 if (use_sequence_mode_)
560 frame_processor_->SetSequenceMode(true);
561
562 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
563 EXPECT_TRUE(ProcessFrames("0K 10K", ""));
564 EXPECT_TRUE(in_coded_frame_group());
565 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
566 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
567
568 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
569 EXPECT_TRUE(ProcessFrames("20K 30K", ""));
570 EXPECT_TRUE(in_coded_frame_group());
571 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
572 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
573
574 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
575 }
576
TEST_P(FrameProcessorTest,AudioOnly_NonSequentialProcessFrames)577 TEST_P(FrameProcessorTest, AudioOnly_NonSequentialProcessFrames) {
578 // Tests A: P(A20,A30)+P(A0,A10) ->
579 // if sequence mode: TSO==-20 after first P(), 20 after second P(), and
580 // a(20@0,a30@10,a0@20,a10@30)
581 // if segments mode: TSO==0,(a0,a10,a20,a30)
582 InSequence s;
583 AddTestTracks(HAS_AUDIO);
584 if (use_sequence_mode_) {
585 frame_processor_->SetSequenceMode(true);
586 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
587 } else {
588 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
589 }
590
591 EXPECT_TRUE(ProcessFrames("20K 30K", ""));
592 EXPECT_TRUE(in_coded_frame_group());
593
594 if (use_sequence_mode_) {
595 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
596 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
597 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
598 } else {
599 CheckExpectedRangesByTimestamp(audio_.get(), "{ [20,40) }");
600 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
601 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
602 }
603
604 EXPECT_TRUE(ProcessFrames("0K 10K", ""));
605 EXPECT_TRUE(in_coded_frame_group());
606
607 if (use_sequence_mode_) {
608 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
609 EXPECT_EQ(Milliseconds(20), timestamp_offset_);
610 CheckReadsThenReadStalls(audio_.get(), "0:20 10:30 20:0 30:10");
611 } else {
612 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
613 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
614 // Re-seek to 0ms now that we've appended data earlier than what has already
615 // satisfied our initial seek to start, above.
616 SeekStream(audio_.get(), Milliseconds(0));
617 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
618 }
619 }
620
TEST_P(FrameProcessorTest,AudioVideo_SequentialProcessFrames)621 TEST_P(FrameProcessorTest, AudioVideo_SequentialProcessFrames) {
622 // Tests AV: P(A0,A10;V0k,V10,V20)+P(A20,A30,A40,V30) ->
623 // (a0,a10,a20,a30,a40);(v0,v10,v20,v30)
624 InSequence s;
625 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
626 if (use_sequence_mode_) {
627 frame_processor_->SetSequenceMode(true);
628 EXPECT_CALL(callbacks_,
629 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
630 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
631 }
632
633 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(30)));
634 EXPECT_TRUE(ProcessFrames("0K 10K", "0K 10 20"));
635 EXPECT_TRUE(in_coded_frame_group());
636 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
637 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
638 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,30) }");
639
640 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(50)));
641 EXPECT_TRUE(ProcessFrames("20K 30K 40K", "30"));
642 EXPECT_TRUE(in_coded_frame_group());
643 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
644 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,50) }");
645 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,40) }");
646
647 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30 40");
648 CheckReadsThenReadStalls(video_.get(), "0 10 20 30");
649 }
650
TEST_P(FrameProcessorTest,AudioVideo_Discontinuity)651 TEST_P(FrameProcessorTest, AudioVideo_Discontinuity) {
652 // Tests AV: P(A0,A10,A30,A40,A50;V0key,V10,V40,V50key) ->
653 // if sequence mode: TSO==10,(a0,a10,a30,a40,a50@60);(v0,v10,v50@60)
654 // if segments mode: TSO==0,(a0,a10,a30,a40,a50);(v0,v10,v50)
655 // This assumes A40K is processed before V40, which depends currently on
656 // MergeBufferQueues() behavior.
657 InSequence s;
658 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
659 if (use_sequence_mode_) {
660 frame_processor_->SetSequenceMode(true);
661 EXPECT_CALL(callbacks_,
662 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
663 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
664 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(70)));
665 } else {
666 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
667 }
668
669 EXPECT_TRUE(ProcessFrames("0K 10K 30K 40K 50K", "0K 10 40 50K"));
670 EXPECT_TRUE(in_coded_frame_group());
671
672 if (use_sequence_mode_) {
673 EXPECT_EQ(Milliseconds(10), timestamp_offset_);
674 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,70) }");
675 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,20) [60,70) }");
676 CheckReadsThenReadStalls(audio_.get(), "0 10 30 40 60:50");
677 CheckReadsThenReadStalls(video_.get(), "0 10");
678 SeekStream(video_.get(), Milliseconds(60));
679 CheckReadsThenReadStalls(video_.get(), "60:50");
680 } else {
681 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
682 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,60) }");
683 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,20) [50,60) }");
684 CheckReadsThenReadStalls(audio_.get(), "0 10 30 40 50");
685 CheckReadsThenReadStalls(video_.get(), "0 10");
686 SeekStream(video_.get(), Milliseconds(50));
687 CheckReadsThenReadStalls(video_.get(), "50");
688 }
689 }
690
TEST_P(FrameProcessorTest,AudioVideo_Discontinuity_TimestampOffset)691 TEST_P(FrameProcessorTest, AudioVideo_Discontinuity_TimestampOffset) {
692 InSequence s;
693 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
694 frame_processor_->SetSequenceMode(use_sequence_mode_);
695 if (use_sequence_mode_) {
696 EXPECT_CALL(callbacks_,
697 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
698 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
699 }
700
701 // Start a coded frame group at time 100ms. Note the jagged start still uses
702 // the coded frame group's start time as the range start for both streams.
703 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
704 SetTimestampOffset(Milliseconds(100));
705 EXPECT_TRUE(ProcessFrames("0K 10K 20K", "10K 20K 30K"));
706 EXPECT_EQ(Milliseconds(100), timestamp_offset_);
707 EXPECT_TRUE(in_coded_frame_group());
708 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
709 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) }");
710
711 // Test the behavior of both 'sequence' and 'segments' mode if the coded frame
712 // sequence jumps forward beyond the normal discontinuity threshold.
713 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(240)));
714 SetTimestampOffset(Milliseconds(200));
715 EXPECT_TRUE(ProcessFrames("0K 10K 20K", "10K 20K 30K"));
716 EXPECT_EQ(Milliseconds(200), timestamp_offset_);
717 EXPECT_TRUE(in_coded_frame_group());
718 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) [200,230) }");
719 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [200,240) }");
720
721 // Test the behavior when timestampOffset adjustment causes next frames to be
722 // in the past relative to the previously processed frame and triggers a new
723 // coded frame group.
724 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(95)));
725 SetTimestampOffset(Milliseconds(55));
726 EXPECT_TRUE(ProcessFrames("0K 10K 20K", "10K 20K 30K"));
727 EXPECT_EQ(Milliseconds(55), timestamp_offset_);
728 EXPECT_TRUE(in_coded_frame_group());
729 // The new audio range is not within SourceBufferStream's coalescing threshold
730 // relative to the next range, but the new video range is within the
731 // threshold.
732 CheckExpectedRangesByTimestamp(audio_.get(),
733 "{ [55,85) [100,130) [200,230) }");
734 // Note that the range adjacency logic used in this case considers
735 // DTS 85 to be close enough to [100,140), even though the first DTS in video
736 // range [100,140) is actually 110. The muxed data started a coded frame
737 // group at time 100, informing the adjacency logic.
738 CheckExpectedRangesByTimestamp(video_.get(), "{ [55,140) [200,240) }");
739
740 // Verify the buffers.
741 // Re-seek now that we've appended data earlier than what already satisfied
742 // our initial seek to start.
743 SeekStream(audio_.get(), Milliseconds(55));
744 CheckReadsThenReadStalls(audio_.get(), "55:0 65:10 75:20");
745 SeekStream(audio_.get(), Milliseconds(100));
746 CheckReadsThenReadStalls(audio_.get(), "100:0 110:10 120:20");
747 SeekStream(audio_.get(), Milliseconds(200));
748 CheckReadsThenReadStalls(audio_.get(), "200:0 210:10 220:20");
749
750 SeekStream(video_.get(), Milliseconds(55));
751 CheckReadsThenReadStalls(video_.get(),
752 "65:10 75:20 85:30 110:10 120:20 130:30");
753 SeekStream(video_.get(), Milliseconds(200));
754 CheckReadsThenReadStalls(video_.get(), "210:10 220:20 230:30");
755 }
756
TEST_P(FrameProcessorTest,AudioVideo_OutOfSequence_After_Discontinuity)757 TEST_P(FrameProcessorTest, AudioVideo_OutOfSequence_After_Discontinuity) {
758 // Once a discontinuity is detected (and all tracks drop everything until the
759 // next keyframe per each track), we should gracefully handle the case where
760 // some tracks' first keyframe after the discontinuity are appended after, but
761 // end up earlier in timeline than some other track(s). In particular, we
762 // shouldn't notify all tracks that a new coded frame group is starting and
763 // begin dropping leading non-keyframes from all tracks. Rather, we should
764 // notify just the track encountering this new type of discontinuity. Since
765 // MSE doesn't require all media segments to contain media from every track,
766 // these append sequences can occur.
767 InSequence s;
768 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
769 frame_processor_->SetSequenceMode(use_sequence_mode_);
770
771 // Begin with a simple set of appends for all tracks.
772 if (use_sequence_mode_) {
773 // Allow room in the timeline for the last audio append (50K, below) in this
774 // test to remain within default append window [0, +Infinity]. Moving the
775 // sequence mode appends to begin at time 100ms, the same time as the first
776 // append, below, results in a -20ms offset (instead of a -120ms offset)
777 // applied to frames beginning at the first frame after the discontinuity
778 // caused by the video append at 160K, below.
779 SetTimestampOffset(Milliseconds(100));
780 EXPECT_CALL(callbacks_,
781 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
782 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
783 }
784 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
785 EXPECT_TRUE(ProcessFrames("100K 110K 120K", "110K 120K 130K"));
786 EXPECT_TRUE(in_coded_frame_group());
787 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
788 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
789 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) }");
790
791 // Trigger (normal) discontinuity with one track (video).
792 if (use_sequence_mode_)
793 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(150)));
794 else
795 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(170)));
796
797 EXPECT_TRUE(ProcessFrames("", "160K"));
798 EXPECT_TRUE(in_coded_frame_group());
799
800 if (use_sequence_mode_) {
801 // The new video buffer is relocated into [140,150).
802 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
803 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
804 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,150) }");
805 } else {
806 // The new video buffer is at [160,170).
807 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
808 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
809 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [160,170) }");
810 }
811
812 // Append to the other track (audio) with lower time than the video frame we
813 // just appended. Append with a timestamp such that segments mode demonstrates
814 // we don't retroactively extend the new video buffer appended above's range
815 // start back to this audio start time.
816 if (use_sequence_mode_)
817 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(150)));
818 else
819 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(170)));
820
821 EXPECT_TRUE(ProcessFrames("50K", ""));
822 EXPECT_TRUE(in_coded_frame_group());
823
824 // Because this is the first audio buffer appended following the discontinuity
825 // detected while appending the video frame, above, a new coded frame group
826 // for video is not triggered.
827 if (use_sequence_mode_) {
828 // The new audio buffer is relocated into [30,40). Note the muxed 'sequence'
829 // mode append mode results in a buffered range gap in this case.
830 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
831 CheckExpectedRangesByTimestamp(audio_.get(), "{ [30,40) [100,130) }");
832 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,150) }");
833 } else {
834 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
835 CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) [100,130) }");
836 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [160,170) }");
837 }
838
839 // Finally, append a non-keyframe to the first track (video), to continue the
840 // GOP that started the normal discontinuity on the previous video append.
841 if (use_sequence_mode_)
842 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(160)));
843 else
844 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(180)));
845
846 EXPECT_TRUE(ProcessFrames("", "170"));
847 EXPECT_TRUE(in_coded_frame_group());
848
849 // Verify the final buffers. First, re-seek audio since we appended data
850 // earlier than what already satisfied our initial seek to start. We satisfy
851 // the seek with the first buffer in [0,1000).
852 SeekStream(audio_.get(), Milliseconds(0));
853 if (use_sequence_mode_) {
854 // The new video buffer is relocated into [150,160).
855 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
856 CheckExpectedRangesByTimestamp(audio_.get(), "{ [30,40) [100,130) }");
857 CheckReadsThenReadStalls(audio_.get(), "30:50");
858 SeekStream(audio_.get(), Milliseconds(100));
859 CheckReadsThenReadStalls(audio_.get(), "100 110 120");
860
861 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,160) }");
862 CheckReadsThenReadStalls(video_.get(), "110 120 130 140:160 150:170");
863 } else {
864 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
865 CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) [100,130) }");
866 CheckReadsThenReadStalls(audio_.get(), "50");
867 SeekStream(audio_.get(), Milliseconds(100));
868 CheckReadsThenReadStalls(audio_.get(), "100 110 120");
869
870 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [160,180) }");
871 CheckReadsThenReadStalls(video_.get(), "110 120 130");
872 SeekStream(video_.get(), Milliseconds(160));
873 CheckReadsThenReadStalls(video_.get(), "160 170");
874 }
875 }
876
TEST_P(FrameProcessorTest,AppendWindowFilterOfNegativeBufferTimestampsWithPrerollDiscard)877 TEST_P(FrameProcessorTest,
878 AppendWindowFilterOfNegativeBufferTimestampsWithPrerollDiscard) {
879 InSequence s;
880 AddTestTracks(HAS_AUDIO);
881 if (use_sequence_mode_)
882 frame_processor_->SetSequenceMode(true);
883
884 SetTimestampOffset(Milliseconds(-20));
885 EXPECT_MEDIA_LOG(DroppedFrame("audio", -20000));
886 EXPECT_MEDIA_LOG(DroppedFrame("audio", -10000));
887 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
888 EXPECT_TRUE(ProcessFrames("0K 10K 20K", ""));
889 EXPECT_TRUE(in_coded_frame_group());
890 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
891 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) }");
892 CheckReadsThenReadStalls(audio_.get(), "0:10P 0:20");
893 }
894
TEST_P(FrameProcessorTest,AppendWindowFilterWithInexactPreroll)895 TEST_P(FrameProcessorTest, AppendWindowFilterWithInexactPreroll) {
896 InSequence s;
897 AddTestTracks(HAS_AUDIO);
898 if (use_sequence_mode_)
899 frame_processor_->SetSequenceMode(true);
900 SetTimestampOffset(Milliseconds(-10));
901 EXPECT_MEDIA_LOG(DroppedFrame("audio", -10000));
902 EXPECT_MEDIA_LOG(TruncatedFrame(-250, 9750, "start", 0));
903 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
904 EXPECT_TRUE(ProcessFrames("0K 9.75K 20K", ""));
905 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
906 CheckReadsThenReadStalls(audio_.get(), "0P 0:9.75 10:20");
907 }
908
TEST_P(FrameProcessorTest,AppendWindowFilterWithInexactPreroll_2)909 TEST_P(FrameProcessorTest, AppendWindowFilterWithInexactPreroll_2) {
910 InSequence s;
911 AddTestTracks(HAS_AUDIO);
912 if (use_sequence_mode_)
913 frame_processor_->SetSequenceMode(true);
914 SetTimestampOffset(Milliseconds(-10));
915
916 EXPECT_MEDIA_LOG(DroppedFrame("audio", -10000));
917 // Splice trimming checks are done on every audio frame following either a
918 // discontinuity or the beginning of ProcessFrames(), and are also done on
919 // audio frames with PTS not directly continuous with the highest frame end
920 // PTS already processed.
921 if (use_sequence_mode_)
922 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(-10)));
923 else
924 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(0)));
925 EXPECT_TRUE(ProcessFrames("0K", ""));
926
927 EXPECT_CALL(callbacks_, PossibleDurationIncrease(
928 base::TimeDelta::FromMicroseconds(10250)));
929 EXPECT_TRUE(ProcessFrames("10.25K", ""));
930
931 EXPECT_MEDIA_LOG(SkippingSpliceTooLittleOverlap(10000, 250));
932 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
933 EXPECT_TRUE(ProcessFrames("20K", ""));
934
935 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
936 CheckReadsThenReadStalls(audio_.get(), "0P 0:10.25 10:20");
937 }
938
TEST_P(FrameProcessorTest,AllowNegativeFramePTSAndDTSBeforeOffsetAdjustment)939 TEST_P(FrameProcessorTest, AllowNegativeFramePTSAndDTSBeforeOffsetAdjustment) {
940 InSequence s;
941 AddTestTracks(HAS_AUDIO);
942 if (use_sequence_mode_) {
943 frame_processor_->SetSequenceMode(true);
944 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(30)));
945 } else {
946 EXPECT_MEDIA_LOG(TruncatedFrame(-5000, 5000, "start", 0));
947 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(25)));
948 }
949
950 EXPECT_TRUE(ProcessFrames("-5K 5K 15K", ""));
951
952 if (use_sequence_mode_) {
953 EXPECT_EQ(Milliseconds(5), timestamp_offset_);
954 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,30) }");
955 CheckReadsThenReadStalls(audio_.get(), "0:-5 10:5 20:15");
956 } else {
957 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
958 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,25) }");
959 CheckReadsThenReadStalls(audio_.get(), "0:-5 5 15");
960 }
961 }
962
TEST_P(FrameProcessorTest,PartialAppendWindowFilterNoDiscontinuity)963 TEST_P(FrameProcessorTest, PartialAppendWindowFilterNoDiscontinuity) {
964 // Tests that spurious discontinuity is not introduced by a partially
965 // trimmed frame.
966 append_window_start_ = Milliseconds(7);
967
968 InSequence s;
969 AddTestTracks(HAS_AUDIO);
970 if (use_sequence_mode_)
971 frame_processor_->SetSequenceMode(true);
972 EXPECT_MEDIA_LOG(TruncatedFrame(0, 10000, "start", 7000));
973 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(29)));
974
975 EXPECT_TRUE(ProcessFrames("0K 19K", ""));
976
977 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
978 CheckExpectedRangesByTimestamp(audio_.get(), "{ [7,29) }");
979 CheckReadsThenReadStalls(audio_.get(), "7:0 19");
980 }
981
TEST_P(FrameProcessorTest,PartialAppendWindowFilterNoDiscontinuity_DtsAfterPts)982 TEST_P(FrameProcessorTest,
983 PartialAppendWindowFilterNoDiscontinuity_DtsAfterPts) {
984 // Tests that spurious discontinuity is not introduced by a partially trimmed
985 // frame that originally had DTS > PTS.
986 InSequence s;
987 AddTestTracks(HAS_AUDIO);
988
989 if (use_sequence_mode_) {
990 frame_processor_->SetSequenceMode(true);
991 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
992 } else {
993 EXPECT_MEDIA_LOG(TruncatedFrame(-7000, 3000, "start", 0));
994 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(13)));
995 }
996
997 // Process a sequence of two audio frames:
998 // A: PTS -7ms, DTS 10ms, duration 10ms, keyframe
999 // B: PTS 3ms, DTS 20ms, duration 10ms, keyframe
1000 EXPECT_TRUE(ProcessFrames("-7|10K 3|20K", ""));
1001
1002 if (use_sequence_mode_) {
1003 // Sequence mode detected that frame A needs to be relocated 7ms into the
1004 // future to begin the sequence at time 0. There is no append window
1005 // filtering because the PTS result of the relocation is within the append
1006 // window of [0,+Infinity).
1007 // Frame A is relocated by 7 to PTS 0, DTS 17, duration 10.
1008 // Frame B is relocated by 7 to PTS 10, DTS 27, duration 10.
1009 EXPECT_EQ(Milliseconds(7), timestamp_offset_);
1010
1011 // Start of frame A (0) through end of frame B (10+10).
1012 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
1013
1014 // Frame A is now at PTS 0 (originally at PTS -7)
1015 // Frame B is now at PTS 10 (originally at PTS 3)
1016 CheckReadsThenReadStalls(audio_.get(), "0:-7 10:3");
1017 } else {
1018 // Segments mode does not update timestampOffset automatically, so it
1019 // remained 0 and neither frame was relocated by timestampOffset.
1020 // Frame A's start *was* relocated by append window partial audio cropping:
1021 // Append window filtering (done by PTS, regardless of range buffering API)
1022 // did a partial crop of the first 7ms of frame A which was before
1023 // the default append window start time 0, and moved both the PTS and DTS of
1024 // frame A forward by 7 and reduced its duration by 7. Frame B was fully
1025 // inside the append window and remained uncropped and unrelocated.
1026 // Frame A is buffered at PTS -7+7=0, DTS 10+7=17, duration 10-7=3.
1027 // Frame B is buffered at PTS 3, DTS 20, duration 10.
1028 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1029
1030 // Start of frame A (0) through end of frame B (3+10).
1031 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,13) }");
1032
1033 // Frame A is now at PTS 0 (originally at PTS -7)
1034 // Frame B is now at PTS 3 (same as it was originally)
1035 CheckReadsThenReadStalls(audio_.get(), "0:-7 3");
1036 }
1037 }
1038
TEST_P(FrameProcessorTest,PartialAppendWindowFilterNoNewMediaSegment)1039 TEST_P(FrameProcessorTest, PartialAppendWindowFilterNoNewMediaSegment) {
1040 // Tests that a new media segment is not forcibly signalled for audio frame
1041 // partial front trim, to prevent incorrect introduction of a discontinuity
1042 // and potentially a non-keyframe video frame to be processed next after the
1043 // discontinuity.
1044 InSequence s;
1045 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
1046 frame_processor_->SetSequenceMode(use_sequence_mode_);
1047 if (use_sequence_mode_) {
1048 EXPECT_CALL(callbacks_,
1049 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
1050 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
1051 }
1052 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1053 EXPECT_TRUE(ProcessFrames("", "0K"));
1054 EXPECT_MEDIA_LOG(TruncatedFrame(-5000, 5000, "start", 0));
1055 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1056 EXPECT_TRUE(ProcessFrames("-5K", ""));
1057 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
1058 EXPECT_TRUE(ProcessFrames("", "10"));
1059
1060 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1061 EXPECT_TRUE(in_coded_frame_group());
1062 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,5) }");
1063 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,20) }");
1064 CheckReadsThenReadStalls(audio_.get(), "0:-5");
1065 CheckReadsThenReadStalls(video_.get(), "0 10");
1066 }
1067
TEST_P(FrameProcessorTest,AudioOnly_SequenceModeContinuityAcrossReset)1068 TEST_P(FrameProcessorTest, AudioOnly_SequenceModeContinuityAcrossReset) {
1069 if (!use_sequence_mode_) {
1070 DVLOG(1) << "Skipping segments mode variant; inapplicable to this case.";
1071 return;
1072 }
1073
1074 InSequence s;
1075 AddTestTracks(HAS_AUDIO);
1076 frame_processor_->SetSequenceMode(true);
1077 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1078 EXPECT_TRUE(ProcessFrames("0K", ""));
1079 frame_processor_->Reset();
1080 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
1081 EXPECT_TRUE(ProcessFrames("100K", ""));
1082
1083 EXPECT_EQ(Milliseconds(-90), timestamp_offset_);
1084 EXPECT_TRUE(in_coded_frame_group());
1085 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
1086 CheckReadsThenReadStalls(audio_.get(), "0 10:100");
1087 }
1088
TEST_P(FrameProcessorTest,PartialAppendWindowZeroDurationPreroll)1089 TEST_P(FrameProcessorTest, PartialAppendWindowZeroDurationPreroll) {
1090 InSequence s;
1091 AddTestTracks(HAS_AUDIO);
1092 frame_processor_->SetSequenceMode(use_sequence_mode_);
1093
1094 append_window_start_ = Milliseconds(5);
1095
1096 EXPECT_MEDIA_LOG(DroppedFrame("audio", use_sequence_mode_ ? 0 : 4000));
1097 // Append a 0 duration frame that falls just before the append window.
1098 frame_duration_ = Milliseconds(0);
1099 EXPECT_FALSE(in_coded_frame_group());
1100 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(0)));
1101 EXPECT_TRUE(ProcessFrames("4K", ""));
1102 // Verify buffer is not part of ranges. It should be silently saved for
1103 // preroll for future append.
1104 CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
1105 CheckReadsThenReadStalls(audio_.get(), "");
1106 EXPECT_FALSE(in_coded_frame_group());
1107
1108 // Abort the reads from last stall. We don't want those reads to "complete"
1109 // when we append below. We will initiate new reads to confirm the buffer
1110 // looks as we expect.
1111 SeekStream(audio_.get(), Milliseconds(0));
1112
1113 if (use_sequence_mode_) {
1114 EXPECT_MEDIA_LOG(TruncatedFrame(0, 10000, "start", 5000));
1115 } else {
1116 EXPECT_MEDIA_LOG(TruncatedFrame(4000, 14000, "start", 5000));
1117 }
1118 // Append a frame with 10ms duration, with 9ms falling after the window start.
1119 EXPECT_CALL(callbacks_, PossibleDurationIncrease(
1120 Milliseconds(use_sequence_mode_ ? 10 : 14)));
1121 frame_duration_ = Milliseconds(10);
1122 EXPECT_TRUE(ProcessFrames("4K", ""));
1123 EXPECT_TRUE(in_coded_frame_group());
1124
1125 // Verify range updated to reflect last append was processed and trimmed, and
1126 // also that zero duration buffer was saved and attached as preroll.
1127 if (use_sequence_mode_) {
1128 // For sequence mode, append window trimming is applied after the append
1129 // is adjusted for timestampOffset. Basically, everything gets rebased to 0
1130 // and trimming then removes 5 seconds from the front.
1131 CheckExpectedRangesByTimestamp(audio_.get(), "{ [5,10) }");
1132 CheckReadsThenReadStalls(audio_.get(), "5:4P 5:4");
1133 } else { // segments mode
1134 CheckExpectedRangesByTimestamp(audio_.get(), "{ [5,14) }");
1135 CheckReadsThenReadStalls(audio_.get(), "5:4P 5:4");
1136 }
1137
1138 // Verify the preroll buffer still has zero duration.
1139 StreamParserBuffer* last_read_parser_buffer =
1140 static_cast<StreamParserBuffer*>(last_read_buffer_.get());
1141 ASSERT_EQ(Milliseconds(0),
1142 last_read_parser_buffer->preroll_buffer()->duration());
1143 }
1144
TEST_P(FrameProcessorTest,OOOKeyframePrecededByDependantNonKeyframeShouldWarn)1145 TEST_P(FrameProcessorTest,
1146 OOOKeyframePrecededByDependantNonKeyframeShouldWarn) {
1147 InSequence s;
1148 AddTestTracks(HAS_VIDEO);
1149 frame_processor_->SetSequenceMode(use_sequence_mode_);
1150
1151 if (use_sequence_mode_) {
1152 // Allow room in the timeline for the last video append (40|70, below) in
1153 // this test to remain within default append window [0, +Infinity]. Moving
1154 // the sequence mode appends to begin at time 50ms, the same time as the
1155 // first append, below, also results in identical expectation checks for
1156 // buffered ranges and buffer reads for both segments and sequence modes.
1157 SetTimestampOffset(Milliseconds(50));
1158 }
1159
1160 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(70)));
1161 EXPECT_TRUE(ProcessFrames("", "50K 60"));
1162
1163 CheckExpectedRangesByTimestamp(video_.get(), "{ [50,70) }");
1164
1165 EXPECT_CALL(callbacks_,
1166 OnParseWarning(
1167 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1168 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.05", "0.04"));
1169 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(70)));
1170 EXPECT_TRUE(ProcessFrames("", "40|70")); // PTS=40, DTS=70
1171
1172 // This reflects the expectation that PTS start is not "pulled backward" for
1173 // the new frame at PTS=40 because current spec doesn't support SAP Type 2; it
1174 // has no steps in the coded frame processing algorithm that would do that
1175 // "pulling backward". See https://github.com/w3c/media-source/issues/187.
1176 CheckExpectedRangesByTimestamp(video_.get(), "{ [50,70) }");
1177
1178 SeekStream(video_.get(), Milliseconds(0));
1179 CheckReadsThenReadStalls(video_.get(), "50 60 40");
1180 }
1181
TEST_P(FrameProcessorTest,OOOKeyframePts_1)1182 TEST_P(FrameProcessorTest, OOOKeyframePts_1) {
1183 InSequence s;
1184 AddTestTracks(HAS_AUDIO);
1185 frame_processor_->SetSequenceMode(use_sequence_mode_);
1186
1187 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1010)));
1188 // Note that the following does not contain a DTS continuity, but *does*
1189 // contain a PTS discontinuity (keyframe at 0.1s after keyframe at 1s).
1190 EXPECT_TRUE(ProcessFrames("0K 1000|10K 100|20K", ""));
1191
1192 // Force sequence mode to place the next frames where segments mode would put
1193 // them, to simplify this test case.
1194 if (use_sequence_mode_)
1195 SetTimestampOffset(Milliseconds(500));
1196
1197 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(510)));
1198 EXPECT_TRUE(ProcessFrames("500|100K", ""));
1199 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1200
1201 // Note that the PTS discontinuity (100ms) in the first ProcessFrames() call,
1202 // above, overlaps the previously buffered range [0,1010), so the frame at
1203 // 100ms is processed with an adjusted coded frame group start to be 0.001ms,
1204 // which is just after the highest timestamp before it in the overlapped
1205 // range. This enables it to be continuous with the frame before it. The
1206 // remainder of the overlapped range (the buffer at [1000,1010)) is adjusted
1207 // to have a range start time at the split point (110), and is within fudge
1208 // room and merged into [0,110). The same happens with the buffer appended
1209 // [500,510).
1210 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,1010) }");
1211 CheckReadsThenReadStalls(audio_.get(), "0 100 500 1000");
1212 }
1213
TEST_P(FrameProcessorTest,OOOKeyframePts_2)1214 TEST_P(FrameProcessorTest, OOOKeyframePts_2) {
1215 InSequence s;
1216 AddTestTracks(HAS_AUDIO);
1217 frame_processor_->SetSequenceMode(use_sequence_mode_);
1218
1219 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1010)));
1220 EXPECT_TRUE(ProcessFrames("0K 1000|10K", ""));
1221
1222 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1010)));
1223 EXPECT_TRUE(ProcessFrames("100|20K", ""));
1224
1225 // Note that the PTS discontinuity (100ms) in the first ProcessFrames() call,
1226 // above, overlaps the previously buffered range [0,1010), so the frame at
1227 // 100ms is processed with an adjusted coded frame group start to be 0.001ms,
1228 // which is just after the highest timestamp before it in the overlapped
1229 // range. This enables it to be continuous with the frame before it. The
1230 // remainder of the overlapped range (the buffer at [1000,1010)) is adjusted
1231 // to have a range start time at the split point (110), and is within fudge
1232 // room and merged into [0,110).
1233 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,1010) }");
1234 CheckReadsThenReadStalls(audio_.get(), "0 100 1000");
1235 }
1236
TEST_P(FrameProcessorTest,AudioNonKeyframeChangedToKeyframe)1237 TEST_P(FrameProcessorTest, AudioNonKeyframeChangedToKeyframe) {
1238 // Verifies that an audio non-keyframe is changed to a keyframe with a media
1239 // log warning. An exact overlap append of the preceding keyframe is also done
1240 // to ensure that the (original non-keyframe) survives (because it was changed
1241 // to a keyframe, so no longer depends on the original preceding keyframe).
1242 // The sequence mode test version uses SetTimestampOffset to make it behave
1243 // like segments mode to simplify the tests.
1244 // Note, see the NonkeyframeAudioBuffering tests to verify buffering of audio
1245 // nonkeyframes for codec(s) that use nonkeyframes.
1246 InSequence s;
1247 AddTestTracks(HAS_AUDIO);
1248 frame_processor_->SetSequenceMode(use_sequence_mode_);
1249
1250 EXPECT_MEDIA_LOG(AudioNonKeyframe(10000, 10000));
1251 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(30)));
1252 EXPECT_TRUE(ProcessFrames("0K 10 20K", ""));
1253
1254 if (use_sequence_mode_)
1255 SetTimestampOffset(Milliseconds(0));
1256
1257 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1258 EXPECT_TRUE(ProcessFrames("0K", ""));
1259
1260 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,30) }");
1261 SeekStream(audio_.get(), Milliseconds(0));
1262 CheckReadsThenReadStalls(audio_.get(), "0 10 20");
1263 }
1264
TEST_P(FrameProcessorTest,TimestampOffsetNegativeDts)1265 TEST_P(FrameProcessorTest, TimestampOffsetNegativeDts) {
1266 // Shift a GOP earlier using timestampOffset such that the GOP
1267 // starts with negative DTS, but PTS 0.
1268 InSequence s;
1269 AddTestTracks(HAS_VIDEO);
1270 frame_processor_->SetSequenceMode(use_sequence_mode_);
1271
1272 if (!use_sequence_mode_) {
1273 // Simulate the offset that sequence mode would apply, to make the results
1274 // the same regardless of sequence vs segments mode.
1275 SetTimestampOffset(Milliseconds(-100));
1276 }
1277
1278 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
1279 EXPECT_TRUE(ProcessFrames("", "100|70K 130|80"));
1280 EXPECT_EQ(Milliseconds(-100), timestamp_offset_);
1281 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,40) }");
1282 SeekStream(video_.get(), Milliseconds(0));
1283 CheckReadsThenReadStalls(video_.get(), "0:100 30:130");
1284 }
1285
TEST_P(FrameProcessorTest,LargeTimestampOffsetJumpForward)1286 TEST_P(FrameProcessorTest, LargeTimestampOffsetJumpForward) {
1287 // Verifies that jumps forward in buffers emitted from the coded frame
1288 // processing algorithm can create discontinuous buffered ranges if those
1289 // jumps are large enough, in both kinds of AppendMode.
1290 InSequence s;
1291 AddTestTracks(HAS_AUDIO);
1292 frame_processor_->SetSequenceMode(use_sequence_mode_);
1293
1294 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1295 EXPECT_TRUE(ProcessFrames("0K", ""));
1296
1297 SetTimestampOffset(Milliseconds(5000));
1298
1299 // Along with the new timestampOffset set above, this should cause a large
1300 // jump forward in both PTS and DTS for both sequence and segments append
1301 // modes.
1302 if (use_sequence_mode_) {
1303 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(5010)));
1304 } else {
1305 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10010)));
1306 }
1307 EXPECT_TRUE(ProcessFrames("5000|100K", ""));
1308 if (use_sequence_mode_) {
1309 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1310 } else {
1311 EXPECT_EQ(Milliseconds(5000), timestamp_offset_);
1312 }
1313
1314 if (use_sequence_mode_) {
1315 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) [5000,5010) }");
1316 CheckReadsThenReadStalls(audio_.get(), "0");
1317 SeekStream(audio_.get(), Milliseconds(5000));
1318 CheckReadsThenReadStalls(audio_.get(), "5000");
1319 } else {
1320 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) [10000,10010) }");
1321 CheckReadsThenReadStalls(audio_.get(), "0");
1322 SeekStream(audio_.get(), Milliseconds(10000));
1323 CheckReadsThenReadStalls(audio_.get(), "10000:5000");
1324 }
1325 }
1326
TEST_P(FrameProcessorTest,ContinuousDts_SapType2_and_PtsJumpForward)1327 TEST_P(FrameProcessorTest, ContinuousDts_SapType2_and_PtsJumpForward) {
1328 InSequence s;
1329 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1330 frame_processor_->SetSequenceMode(use_sequence_mode_);
1331
1332 // Make the sequence mode buffering appear just like segments mode to simplify
1333 // this test case.
1334 if (use_sequence_mode_)
1335 SetTimestampOffset(Milliseconds(1060));
1336
1337 // Note that the PTS of GOP non-keyframes earlier than the keyframe doesn't
1338 // modify the GOP start of the buffered range here. This may change if we
1339 // decide to improve spec for SAP Type 2 GOPs that begin a coded frame group.
1340 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1341 Milliseconds(1060)));
1342 EXPECT_CALL(callbacks_,
1343 OnParseWarning(
1344 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1345 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("1.06", "1"));
1346 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1347 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1348 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1070)));
1349 EXPECT_TRUE(ProcessFrames(
1350 "", "1060|0K 1000|10 1050|20 1010|30 1040|40 1020|50 1030|60"));
1351 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1352 CheckExpectedRangesByTimestamp(video_.get(), "{ [1060,1070) }");
1353
1354 // Process just the keyframe of the next SAP Type 2 GOP in decode continuity
1355 // with the previous one.
1356 // Note that this second GOP is buffered continuous with the first because
1357 // there is no decode discontinuity detected. This results in inclusion of
1358 // the significant PTS jump forward in the same continuous range.
1359 EXPECT_CALL(
1360 callbacks_,
1361 OnGroupStart(DemuxerStream::VIDEO,
1362 DecodeTimestamp::FromPresentationTime(Milliseconds(60)),
1363 Milliseconds(1070)));
1364 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1365 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1140)));
1366 EXPECT_TRUE(ProcessFrames("", "1130|70K"));
1367 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1368 CheckExpectedRangesByTimestamp(video_.get(), "{ [1060,1140) }");
1369
1370 // Process the remainder of the second GOP.
1371 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1372 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1140)));
1373 EXPECT_TRUE(
1374 ProcessFrames("", "1070|80 1120|90 1080|100 1110|110 1090|120 1100|130"));
1375 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1376 CheckExpectedRangesByTimestamp(video_.get(), "{ [1060,1140) }");
1377
1378 // [1060,1140) should demux continuously without read stall in the middle.
1379 SeekStream(video_.get(), Milliseconds(1060));
1380 CheckReadsThenReadStalls(
1381 video_.get(),
1382 "1060 1000 1050 1010 1040 1020 1030 1130 1070 1120 1080 1110 1090 1100");
1383 // Verify that seek and read of the second GOP is correct.
1384 SeekStream(video_.get(), Milliseconds(1130));
1385 CheckReadsThenReadStalls(video_.get(), "1130 1070 1120 1080 1110 1090 1100");
1386 }
1387
TEST_P(FrameProcessorTest,ContinuousDts_NewGopEndOverlapsLastGop_1)1388 TEST_P(FrameProcessorTest, ContinuousDts_NewGopEndOverlapsLastGop_1) {
1389 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1390 // PTS interval overlapping the previous append.
1391 // Tests SAP-Type-1 GOPs, where newly appended GOP overlaps a nonkeyframe of
1392 // the last GOP appended.
1393 InSequence s;
1394 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1395 frame_processor_->SetSequenceMode(use_sequence_mode_);
1396
1397 // Make the sequence mode buffering appear just like segments mode to simplify
1398 // this test case.
1399 if (use_sequence_mode_)
1400 SetTimestampOffset(Milliseconds(100));
1401
1402 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1403 Milliseconds(100)));
1404 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1405 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
1406 EXPECT_TRUE(ProcessFrames("", "100|0K 110|10 120|20 130|30"));
1407 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1408
1409 EXPECT_CALL(
1410 callbacks_,
1411 OnGroupStart(DemuxerStream::VIDEO,
1412 DecodeTimestamp::FromPresentationTime(Milliseconds(30)),
1413 Milliseconds(125)));
1414 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1415 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(165)));
1416 EXPECT_TRUE(ProcessFrames("", "125|40K 135|50 145|60 155|70"));
1417 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1418
1419 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,165) }");
1420 CheckReadsThenReadStalls(video_.get(), "100 110 120 125 135 145 155");
1421 }
1422
TEST_P(FrameProcessorTest,ContinuousDts_NewGopEndOverlapsLastGop_2)1423 TEST_P(FrameProcessorTest, ContinuousDts_NewGopEndOverlapsLastGop_2) {
1424 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1425 // PTS interval overlapping the previous append.
1426 // Tests SAP-Type 1 GOPs, where newly appended GOP overlaps the keyframe of
1427 // the last GOP appended.
1428 InSequence s;
1429 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1430 frame_processor_->SetSequenceMode(use_sequence_mode_);
1431
1432 // Make the sequence mode buffering appear just like segments mode to simplify
1433 // this test case.
1434 if (use_sequence_mode_)
1435 SetTimestampOffset(Milliseconds(100));
1436
1437 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1438 Milliseconds(100)));
1439 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1440 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
1441 EXPECT_TRUE(ProcessFrames("", "100|0K 110|10 120|20K 130|30"));
1442 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1443
1444 EXPECT_CALL(
1445 callbacks_,
1446 OnGroupStart(DemuxerStream::VIDEO,
1447 DecodeTimestamp::FromPresentationTime(Milliseconds(30)),
1448 Milliseconds(115)));
1449 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1450 // TODO(wolenetz): Duration shouldn't be allowed to possibly increase to 140ms
1451 // here. See https://crbug.com/763620.
1452 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
1453 EXPECT_TRUE(ProcessFrames("", "115|40K 125|50"));
1454 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1455
1456 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,135) }");
1457 CheckReadsThenReadStalls(video_.get(), "100 110 115 125");
1458 }
1459
TEST_P(FrameProcessorTest,ContinuousDts_NewSap2GopEndOverlapsLastGop_1)1460 TEST_P(FrameProcessorTest, ContinuousDts_NewSap2GopEndOverlapsLastGop_1) {
1461 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1462 // PTS interval overlapping the previous append, using SAP Type 2 GOPs.
1463 // Tests SAP-Type 2 GOPs, where newly appended GOP overlaps nonkeyframes of
1464 // the last GOP appended.
1465 InSequence s;
1466 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1467 frame_processor_->SetSequenceMode(use_sequence_mode_);
1468
1469 // Make the sequence mode buffering appear just like segments mode to simplify
1470 // this test case.
1471 if (use_sequence_mode_)
1472 SetTimestampOffset(Milliseconds(120));
1473
1474 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1475 Milliseconds(120)));
1476 EXPECT_CALL(callbacks_,
1477 OnParseWarning(
1478 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1479 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.12", "0.1"));
1480 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1481 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1482 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
1483 EXPECT_TRUE(ProcessFrames("", "120|0K 100|10 130|20 110|30"));
1484 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1485
1486 // Note, we *don't* expect another OnGroupStart during the next ProcessFrames,
1487 // since the next GOP's keyframe PTS is after the first GOP and close enough
1488 // to be assured adjacent.
1489 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1490 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1491 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(165)));
1492 EXPECT_TRUE(ProcessFrames("", "145|40K 125|50 155|60 135|70"));
1493 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1494
1495 CheckExpectedRangesByTimestamp(video_.get(), "{ [120,165) }");
1496 // [120,165) should demux continuously without read stall in the middle.
1497 CheckReadsThenReadStalls(video_.get(), "120 100 130 110 145 125 155 135");
1498 // Verify that seek and read of the second GOP is correct.
1499 SeekStream(video_.get(), Milliseconds(145));
1500 CheckReadsThenReadStalls(video_.get(), "145 125 155 135");
1501 }
1502
TEST_P(FrameProcessorTest,ContinuousDts_NewSap2GopEndOverlapsLastGop_2)1503 TEST_P(FrameProcessorTest, ContinuousDts_NewSap2GopEndOverlapsLastGop_2) {
1504 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1505 // PTS interval overlapping the previous append, using SAP Type 2 GOPs.
1506 // Tests SAP-Type 2 GOPs, where newly appended GOP overlaps the keyframe of
1507 // last GOP appended.
1508 InSequence s;
1509 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1510 frame_processor_->SetSequenceMode(use_sequence_mode_);
1511
1512 // Make the sequence mode buffering appear just like segments mode to simplify
1513 // this test case.
1514 if (use_sequence_mode_)
1515 SetTimestampOffset(Milliseconds(120));
1516
1517 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1518 Milliseconds(120)));
1519 EXPECT_CALL(callbacks_,
1520 OnParseWarning(
1521 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1522 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.12", "0.1"));
1523 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1524 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1525 // There is a second GOP that is SAP-Type-2 within this first ProcessFrames,
1526 // with PTS jumping forward far enough to trigger group start signalling and a
1527 // flush.
1528 EXPECT_CALL(
1529 callbacks_,
1530 OnGroupStart(DemuxerStream::VIDEO,
1531 DecodeTimestamp::FromPresentationTime(Milliseconds(30)),
1532 Milliseconds(140)));
1533 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1534 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(180)));
1535 EXPECT_TRUE(ProcessFrames(
1536 "", "120|0K 100|10 130|20 110|30 160|40K 140|50 170|60 150|70"));
1537 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1538
1539 EXPECT_CALL(
1540 callbacks_,
1541 OnGroupStart(DemuxerStream::VIDEO,
1542 DecodeTimestamp::FromPresentationTime(Milliseconds(70)),
1543 Milliseconds(155)));
1544 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1545 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1546 // TODO(wolenetz): Duration shouldn't be allowed to possibly increase to 180ms
1547 // here. See https://crbug.com/763620.
1548 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(180)));
1549 EXPECT_TRUE(ProcessFrames("", "155|80K 145|90"));
1550 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1551
1552 CheckExpectedRangesByTimestamp(video_.get(), "{ [120,165) }");
1553 // [120,165) should demux continuously without read stall in the middle.
1554 CheckReadsThenReadStalls(video_.get(), "120 100 130 110 155 145");
1555 // Verify seek and read of the second GOP is correct.
1556 SeekStream(video_.get(), Milliseconds(155));
1557 CheckReadsThenReadStalls(video_.get(), "155 145");
1558 }
1559
TEST_P(FrameProcessorTest,ContinuousDts_NewSap2GopEndOverlapsLastGop_3_GopByGop)1560 TEST_P(FrameProcessorTest,
1561 ContinuousDts_NewSap2GopEndOverlapsLastGop_3_GopByGop) {
1562 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1563 // PTS interval overlapping the previous append, using SAP Type 2 GOPs. Tests
1564 // SAP-Type 2 GOPs, where newly appended GOP overlaps enough nonkeyframes of
1565 // the previous GOP such that dropped decode dependencies might cause problems
1566 // if the first nonkeyframe with PTS prior to the GOP's keyframe PTS is
1567 // flushed at the same time as its keyframe, but the second GOP's keyframe PTS
1568 // is close enough to the end of the first GOP's presentation interval to not
1569 // signal a new coded frame group start.
1570 InSequence s;
1571 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1572 frame_processor_->SetSequenceMode(use_sequence_mode_);
1573
1574 // Make the sequence mode buffering appear just like segments mode to simplify
1575 // this test case.
1576 if (use_sequence_mode_)
1577 SetTimestampOffset(Milliseconds(500));
1578
1579 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1580 Milliseconds(500)));
1581 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1582 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(530)));
1583 EXPECT_TRUE(ProcessFrames("", "500|0K 520|10 510|20"));
1584 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,530) }");
1585
1586 EXPECT_CALL(callbacks_,
1587 OnParseWarning(
1588 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1589 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.54", "0.52"));
1590 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1591 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1592 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(550)));
1593 EXPECT_TRUE(ProcessFrames("", "540|30K 520|40 530|50"));
1594
1595 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,550) }");
1596 SeekStream(video_.get(), Milliseconds(500));
1597 CheckReadsThenReadStalls(video_.get(), "500 520 510 540 520 530");
1598 }
1599
TEST_P(FrameProcessorTest,ContinuousDts_NewSap2GopEndOverlapsLastGop_3_FrameByFrame)1600 TEST_P(FrameProcessorTest,
1601 ContinuousDts_NewSap2GopEndOverlapsLastGop_3_FrameByFrame) {
1602 // Tests that the buffered range results match the previous GopByGop test if
1603 // each frame of the second GOP is explicitly appended by the app
1604 // one-at-a-time.
1605 InSequence s;
1606 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1607 frame_processor_->SetSequenceMode(use_sequence_mode_);
1608
1609 // Make the sequence mode buffering appear just like segments mode to simplify
1610 // this test case.
1611 if (use_sequence_mode_)
1612 SetTimestampOffset(Milliseconds(500));
1613
1614 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1615 Milliseconds(500)));
1616 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1617 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(530)));
1618 EXPECT_TRUE(ProcessFrames("", "500|0K 520|10 510|20"));
1619 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,530) }");
1620
1621 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1622 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(550)));
1623 EXPECT_TRUE(ProcessFrames("", "540|30K"));
1624
1625 EXPECT_CALL(callbacks_,
1626 OnParseWarning(
1627 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1628 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.54", "0.52"));
1629 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1630 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(550)));
1631 EXPECT_TRUE(ProcessFrames("", "520|40"));
1632
1633 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1634 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(550)));
1635 EXPECT_TRUE(ProcessFrames("", "530|50"));
1636
1637 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,550) }");
1638 SeekStream(video_.get(), Milliseconds(500));
1639 CheckReadsThenReadStalls(video_.get(), "500 520 510 540 520 530");
1640 }
1641
TEST_P(FrameProcessorTest,ContinuousDts_NewSap2GopEndOverlapsLastGop_4_GopByGop)1642 TEST_P(FrameProcessorTest,
1643 ContinuousDts_NewSap2GopEndOverlapsLastGop_4_GopByGop) {
1644 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1645 // PTS interval overlapping the previous append, using SAP Type 2 GOPs. Tests
1646 // SAP-Type 2 GOPs, where newly appended GOP overlaps enough nonkeyframes of
1647 // the previous GOP such that dropped decode dependencies might cause problems
1648 // if the first nonkeyframe with PTS prior to the GOP's keyframe PTS is
1649 // flushed at the same time as its keyframe.
1650 InSequence s;
1651 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1652 frame_processor_->SetSequenceMode(use_sequence_mode_);
1653
1654 // Make the sequence mode buffering appear just like segments mode to simplify
1655 // this test case.
1656 if (use_sequence_mode_)
1657 SetTimestampOffset(Milliseconds(500));
1658
1659 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1660 Milliseconds(500)));
1661 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1662 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(530)));
1663 EXPECT_TRUE(ProcessFrames("", "500|0K 520|10 510|20"));
1664 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,530) }");
1665
1666 EXPECT_CALL(
1667 callbacks_,
1668 OnGroupStart(DemuxerStream::VIDEO,
1669 DecodeTimestamp::FromPresentationTime(Milliseconds(20)),
1670 Milliseconds(530)));
1671 EXPECT_CALL(callbacks_,
1672 OnParseWarning(
1673 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1674 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.55", "0.52"));
1675 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1676 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1677 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1678 EXPECT_TRUE(ProcessFrames("", "550|30K 520|40 530|50 540|60"));
1679
1680 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,560) }");
1681 SeekStream(video_.get(), Milliseconds(500));
1682 CheckReadsThenReadStalls(video_.get(), "500 520 510 550 520 530 540");
1683 }
1684
TEST_P(FrameProcessorTest,ContinuousDts_NewSap2GopEndOverlapsLastGop_4_FrameByFrame)1685 TEST_P(FrameProcessorTest,
1686 ContinuousDts_NewSap2GopEndOverlapsLastGop_4_FrameByFrame) {
1687 // Tests that the buffered range results match the previous GopByGop test if
1688 // each frame of the second GOP is explicitly appended by the app
1689 // one-at-a-time.
1690 InSequence s;
1691 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1692 frame_processor_->SetSequenceMode(use_sequence_mode_);
1693
1694 // Make the sequence mode buffering appear just like segments mode to simplify
1695 // this test case.
1696 if (use_sequence_mode_)
1697 SetTimestampOffset(Milliseconds(500));
1698
1699 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1700 Milliseconds(500)));
1701 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1702 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(530)));
1703 EXPECT_TRUE(ProcessFrames("", "500|0K 520|10 510|20"));
1704 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,530) }");
1705
1706 EXPECT_CALL(
1707 callbacks_,
1708 OnGroupStart(DemuxerStream::VIDEO,
1709 DecodeTimestamp::FromPresentationTime(Milliseconds(20)),
1710 Milliseconds(530)));
1711 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1712 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1713 EXPECT_TRUE(ProcessFrames("", "550|30K"));
1714
1715 EXPECT_CALL(callbacks_,
1716 OnParseWarning(
1717 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1718 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.55", "0.52"));
1719 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1720 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1721 EXPECT_TRUE(ProcessFrames("", "520|40"));
1722
1723 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1724 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1725 EXPECT_TRUE(ProcessFrames("", "530|50"));
1726
1727 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1728 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1729 EXPECT_TRUE(ProcessFrames("", "540|60"));
1730
1731 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,560) }");
1732 SeekStream(video_.get(), Milliseconds(500));
1733 CheckReadsThenReadStalls(video_.get(), "500 520 510 550 520 530 540");
1734 }
1735
TEST_P(FrameProcessorTest,ContinuousDts_GopKeyframePtsOrder_2_1_3)1736 TEST_P(FrameProcessorTest, ContinuousDts_GopKeyframePtsOrder_2_1_3) {
1737 // White-box test, demonstrating expected behavior for a specially crafted
1738 // sequence that "should" be unusual, but gracefully handled:
1739 // SAP-Type 1 GOPs for simplicity of test. First appended GOP is highest in
1740 // timeline. Second appended GOP is earliest in timeline. Third appended GOP
1741 // is continuous in time with highest end time of first appended GOP. The
1742 // result should be a single continuous range containing just the second and
1743 // third appended GOPs (since the first-appended GOP was overlap-removed from
1744 // the timeline due to being in the gap between the second and third appended
1745 // GOPs). Note that MseTrackBuffer::ResetHighestPresentationTimestamp() done
1746 // at the beginning of the second appended GOP is the key to gracefully
1747 // handling the third appended GOP.
1748 InSequence s;
1749 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1750 frame_processor_->SetSequenceMode(use_sequence_mode_);
1751
1752 // Make the sequence mode buffering appear just like segments mode to simplify
1753 // this test case.
1754 if (use_sequence_mode_)
1755 SetTimestampOffset(Milliseconds(200));
1756
1757 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1758 Milliseconds(200)));
1759 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1760 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(240)));
1761 EXPECT_TRUE(ProcessFrames("", "200|0K 210|10 220|20 230|30"));
1762 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1763 CheckExpectedRangesByTimestamp(video_.get(), "{ [200,240) }");
1764
1765 EXPECT_CALL(
1766 callbacks_,
1767 OnGroupStart(DemuxerStream::VIDEO,
1768 DecodeTimestamp::FromPresentationTime(Milliseconds(30)),
1769 Milliseconds(100)));
1770 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1771 // TODO(wolenetz): Duration shouldn't be allowed to possibly increase to 240ms
1772 // here. See https://crbug.com/763620.
1773 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(240)));
1774 EXPECT_TRUE(ProcessFrames("", "100|40K 110|50 120|60 130|70"));
1775 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1776 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [200,240) }");
1777
1778 EXPECT_CALL(
1779 callbacks_,
1780 OnGroupStart(DemuxerStream::VIDEO,
1781 DecodeTimestamp::FromPresentationTime(Milliseconds(70)),
1782 Milliseconds(140)));
1783 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1784 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(260)));
1785 EXPECT_TRUE(ProcessFrames("", "240|80K 250|90"));
1786 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1787 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,260) }");
1788
1789 SeekStream(video_.get(), Milliseconds(100));
1790 CheckReadsThenReadStalls(video_.get(), "100 110 120 130 240 250");
1791 }
1792
TEST_P(FrameProcessorTest,ContinuousPts_DiscontinuousDts_AcrossGops)1793 TEST_P(FrameProcessorTest, ContinuousPts_DiscontinuousDts_AcrossGops) {
1794 // GOPs which overlap in DTS, but are continuous in PTS should be buffered
1795 // correctly. In particular, monotonic increase of DTS in continuous-in-PTS
1796 // append sequences is not required across GOPs (just within GOPs).
1797 InSequence s;
1798 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1799 frame_processor_->SetSequenceMode(use_sequence_mode_);
1800
1801 // Make the sequence mode buffering appear just like segments mode to simplify
1802 // this test case.
1803 if (use_sequence_mode_)
1804 SetTimestampOffset(Milliseconds(200));
1805
1806 EXPECT_CALL(
1807 callbacks_,
1808 OnGroupStart(DemuxerStream::VIDEO,
1809 DecodeTimestamp::FromPresentationTime(Milliseconds(200)),
1810 Milliseconds(200)));
1811 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1812 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(240)));
1813 EXPECT_TRUE(ProcessFrames("", "200K 210 220 230"));
1814 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1815 CheckExpectedRangesByTimestamp(video_.get(), "{ [200,240) }");
1816
1817 EXPECT_CALL(
1818 callbacks_,
1819 OnGroupStart(DemuxerStream::VIDEO,
1820 DecodeTimestamp::FromPresentationTime(Milliseconds(225)),
1821 Milliseconds(240)));
1822 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1823 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(280)));
1824 // Append a second GOP whose first DTS is below the last DTS of the first GOP,
1825 // but whose PTS interval is continuous with the end of the first GOP.
1826 EXPECT_TRUE(ProcessFrames("", "240|225K 250|235 260|245 270|255"));
1827 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1828 SeekStream(video_.get(), Milliseconds(200));
1829
1830 CheckExpectedRangesByTimestamp(video_.get(), "{ [200,280) }");
1831 CheckReadsThenReadStalls(video_.get(), "200 210 220 230 240 250 260 270");
1832 }
1833
TEST_P(FrameProcessorTest,OnlyKeyframes_ContinuousDts_ContinousPts_1)1834 TEST_P(FrameProcessorTest, OnlyKeyframes_ContinuousDts_ContinousPts_1) {
1835 // Verifies that precisely one group start and one stream append occurs for a
1836 // single continuous set of frames.
1837 InSequence s;
1838 AddTestTracks(HAS_AUDIO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1839 if (use_sequence_mode_)
1840 frame_processor_->SetSequenceMode(true);
1841
1842 // Default test frame duration is 10 milliseconds.
1843
1844 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::AUDIO, DecodeTimestamp(),
1845 base::TimeDelta()));
1846 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1847 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
1848 EXPECT_TRUE(ProcessFrames("0K 10K 20K 30K", ""));
1849 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1850
1851 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
1852 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
1853 }
1854
TEST_P(FrameProcessorTest,OnlyKeyframes_ContinuousDts_ContinuousPts_2)1855 TEST_P(FrameProcessorTest, OnlyKeyframes_ContinuousDts_ContinuousPts_2) {
1856 // Verifies that precisely one group start and one stream append occurs while
1857 // processing a single continuous set of frames that uses fudge room to just
1858 // barely remain adjacent.
1859 InSequence s;
1860 AddTestTracks(HAS_AUDIO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1861 if (use_sequence_mode_)
1862 frame_processor_->SetSequenceMode(true);
1863
1864 frame_duration_ = Milliseconds(5);
1865
1866 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::AUDIO, DecodeTimestamp(),
1867 base::TimeDelta()));
1868 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1869 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(35)));
1870 EXPECT_TRUE(ProcessFrames("0K 10K 20K 30K", ""));
1871 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1872
1873 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,35) }");
1874 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
1875 }
1876
TEST_P(FrameProcessorTest,OnlyKeyframes_ContinuousDts_DiscontinuousPtsJustBeyondFudgeRoom)1877 TEST_P(FrameProcessorTest,
1878 OnlyKeyframes_ContinuousDts_DiscontinuousPtsJustBeyondFudgeRoom) {
1879 // Verifies that multiple group starts and distinct appends occur
1880 // when processing a single DTS-continuous set of frames with PTS deltas that
1881 // just barely exceed the adjacency assumption in FrameProcessor.
1882 InSequence s;
1883 AddTestTracks(HAS_AUDIO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1884 if (use_sequence_mode_)
1885 frame_processor_->SetSequenceMode(true);
1886
1887 frame_duration_ = base::TimeDelta::FromMicroseconds(4999);
1888
1889 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::AUDIO, DecodeTimestamp(),
1890 base::TimeDelta()));
1891 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1892 // Frame "10|5K" following "0K" triggers start of new group and eventual
1893 // append.
1894 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::AUDIO, DecodeTimestamp(),
1895 frame_duration_));
1896 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1897
1898 // Frame "20|10K" following "10|5K" triggers start of new group and eventual
1899 // append.
1900 EXPECT_CALL(
1901 callbacks_,
1902 OnGroupStart(DemuxerStream::AUDIO,
1903 DecodeTimestamp::FromPresentationTime(Milliseconds(5)),
1904 Milliseconds(10) + frame_duration_));
1905 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1906
1907 // Frame "30|15K" following "20|10K" triggers start of new group and
1908 // eventual append.
1909 EXPECT_CALL(
1910 callbacks_,
1911 OnGroupStart(DemuxerStream::AUDIO,
1912 DecodeTimestamp::FromPresentationTime(Milliseconds(10)),
1913 Milliseconds(20) + frame_duration_));
1914 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1915
1916 EXPECT_CALL(callbacks_, PossibleDurationIncrease(
1917 base::TimeDelta::FromMicroseconds(34999)));
1918 EXPECT_TRUE(ProcessFrames("0K 10|5K 20|10K 30|15K", ""));
1919 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1920
1921 // Note that the result is still buffered continuous since DTS was continuous
1922 // and PTS was monotonically increasing (such that each group start was
1923 // signalled by FrameProcessor to be continuous with the end of the previous
1924 // group, if any.)
1925 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,34) }");
1926 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
1927 }
1928
TEST_P(FrameProcessorTest,GroupEndTimestampDecreaseWithinMediaSegmentShouldWarn)1929 TEST_P(FrameProcessorTest,
1930 GroupEndTimestampDecreaseWithinMediaSegmentShouldWarn) {
1931 // This parse warning requires:
1932 // 1) a decode time discontinuity within the set of frames being processed,
1933 // 2) the highest frame end time of any frame successfully processed
1934 // before that discontinuity is higher than the highest frame end time of
1935 // all frames processed after that discontinuity.
1936 // TODO(wolenetz): Adjust this case once direction on spec is informed by
1937 // data. See https://crbug.com/920853 and
1938 // https://github.com/w3c/media-source/issues/203.
1939 if (use_sequence_mode_) {
1940 // Sequence mode modifies the presentation timestamps following a decode
1941 // discontinuity such that this scenario should not repro with that mode.
1942 DVLOG(1) << "Skipping segments mode variant; inapplicable to this case.";
1943 return;
1944 }
1945
1946 InSequence s;
1947 AddTestTracks(HAS_VIDEO);
1948
1949 EXPECT_CALL(callbacks_,
1950 OnParseWarning(SourceBufferParseWarning::
1951 kGroupEndTimestampDecreaseWithinMediaSegment));
1952
1953 frame_duration_ = Milliseconds(10);
1954 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(15)));
1955 EXPECT_TRUE(ProcessFrames("", "0K 10K 5|40K"));
1956 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1957
1958 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,15) }");
1959 CheckReadsThenReadStalls(video_.get(), "0 5");
1960 }
1961
TEST_P(FrameProcessorTest,NonkeyframeAudioBuffering_BasicOperation)1962 TEST_P(FrameProcessorTest, NonkeyframeAudioBuffering_BasicOperation) {
1963 // With the support for audio nonkeyframe buffering enabled, buffer a couple
1964 // continuous groups of audio key and nonkey frames.
1965 // Note, see the AudioNonKeyframeChangedToKeyframe test that tests where
1966 // nonkeyframe audio buffering is not supported, and instead takes a
1967 // workaround that forces all audio to be keyframe.
1968 InSequence s;
1969 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
1970 if (use_sequence_mode_)
1971 frame_processor_->SetSequenceMode(true);
1972
1973 // Default test frame duration is 10 milliseconds.
1974 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(80)));
1975 EXPECT_TRUE(ProcessFrames("0K 10 20 30 40K 50 60 70", ""));
1976 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1977
1978 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,80) }");
1979 CheckReadsAndKeyframenessThenReadStalls(audio_.get(),
1980 "0K 10N 20N 30N 40K 50N 60N 70N");
1981 }
1982
TEST_P(FrameProcessorTest,NonkeyframeAudioBuffering_BasicOverlaps)1983 TEST_P(FrameProcessorTest, NonkeyframeAudioBuffering_BasicOverlaps) {
1984 // With the support for audio nonkeyframe buffering enabled, buffer a few
1985 // groups of audio key and nonkey frames which overlap each other.
1986 // For sequence mode versions, timestampOffset is adjusted to make it act like
1987 // segments mode.
1988 InSequence s;
1989 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
1990 if (use_sequence_mode_) {
1991 frame_processor_->SetSequenceMode(true);
1992 SetTimestampOffset(Milliseconds(10));
1993 }
1994
1995 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
1996 EXPECT_TRUE(ProcessFrames("10K 20 30 40 50", ""));
1997 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1998 CheckExpectedRangesByTimestamp(audio_.get(), "{ [10,60) }");
1999
2000 // End-overlap the last nonkeyframe appended with a keyframe.
2001
2002 if (use_sequence_mode_)
2003 SetTimestampOffset(Milliseconds(50));
2004
2005 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(70)));
2006 EXPECT_TRUE(ProcessFrames("50K 60", ""));
2007 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2008 CheckExpectedRangesByTimestamp(audio_.get(), "{ [10,70) }");
2009
2010 // Front-overlap the original group of frames.
2011
2012 if (use_sequence_mode_)
2013 SetTimestampOffset(Milliseconds(0));
2014
2015 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
2016 EXPECT_TRUE(ProcessFrames("0K 10", ""));
2017 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2018 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,70) }");
2019
2020 SeekStream(audio_.get(), Milliseconds(0));
2021 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "0K 10N 50K 60N");
2022 }
2023
TEST_P(FrameProcessorTest,NonkeyframeAudioBuffering_InitialNonkeyframesNotBuffered)2024 TEST_P(FrameProcessorTest,
2025 NonkeyframeAudioBuffering_InitialNonkeyframesNotBuffered) {
2026 // With the support for audio nonkeyframe buffering enabled, try to buffer
2027 // some frames beginning with a nonkeyframe and observe initial nonkeyframe(s)
2028 // are not buffered.
2029 InSequence s;
2030 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2031 if (use_sequence_mode_)
2032 frame_processor_->SetSequenceMode(true);
2033
2034 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
2035 EXPECT_TRUE(ProcessFrames("0 10 20K 30 40 50", ""));
2036 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2037 CheckExpectedRangesByTimestamp(audio_.get(), "{ [20,60) }");
2038 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "20K 30N 40N 50N");
2039 }
2040
TEST_P(FrameProcessorTest,NonkeyframeAudioBuffering_InvalidDecreasingNonkeyframePts)2041 TEST_P(FrameProcessorTest,
2042 NonkeyframeAudioBuffering_InvalidDecreasingNonkeyframePts) {
2043 // With the support for audio nonkeyframe buffering enabled, try to buffer an
2044 // invalid sequence of nonkeyframes: decreasing presentation timestamps are
2045 // not supported for audio nonkeyframes. For sequence mode versions,
2046 // timestampOffset is adjusted to make it act like segments mode.
2047 InSequence s;
2048 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2049 if (use_sequence_mode_) {
2050 frame_processor_->SetSequenceMode(true);
2051 SetTimestampOffset(Milliseconds(100));
2052 }
2053
2054 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(110)));
2055 EXPECT_TRUE(ProcessFrames("100K", ""));
2056 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2057 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,110) }");
2058
2059 // Processing an audio nonkeyframe with lower PTS than the previous frame
2060 // should fail.
2061 EXPECT_MEDIA_LOG(AudioNonKeyframeOutOfOrder());
2062 EXPECT_FALSE(ProcessFrames("90|110", ""));
2063 }
2064
TEST_P(FrameProcessorTest,NonkeyframeAudioBuffering_ValidDecreasingKeyframePts)2065 TEST_P(FrameProcessorTest,
2066 NonkeyframeAudioBuffering_ValidDecreasingKeyframePts) {
2067 // With the support for audio nonkeyframe buffering enabled, try to buffer a
2068 // valid sequence of key and nonkeyframes: decreasing presentation timestamps
2069 // are supported for keyframes. For sequence mode versions, timestampOffset is
2070 // adjusted to make it act like segments mode.
2071 InSequence s;
2072 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2073 if (use_sequence_mode_) {
2074 frame_processor_->SetSequenceMode(true);
2075 SetTimestampOffset(Milliseconds(100));
2076 }
2077
2078 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(130)));
2079 EXPECT_TRUE(ProcessFrames("100K 110 120", ""));
2080 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2081 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
2082
2083 // Processing an audio keyframe with lower PTS than the previous frame
2084 // should succeed, since it is a keyframe. Here, we use continuous DTS to
2085 // ensure we precisely target the nonkeyframe monotonicity check when a
2086 // keyframe is not required by the track buffer currently (and to make
2087 // sequence mode versions act like segments mode without further manual
2088 // adjustment of timestamp offset.) The original nonkeyframe at PTS 110 should
2089 // be overlap-removed, and the one at PTS 120 should have be removed as a
2090 // result of depending on that removed PTS 110 nonkeyframe.
2091 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(130)));
2092 EXPECT_TRUE(ProcessFrames("110|130K", ""));
2093 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2094 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,120) }");
2095 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "100K 110K");
2096 }
2097
TEST_P(FrameProcessorTest,NonkeyframeAudioBuffering_ValidSameNonKeyframePts_1)2098 TEST_P(FrameProcessorTest,
2099 NonkeyframeAudioBuffering_ValidSameNonKeyframePts_1) {
2100 // With the support for audio nonkeyframe buffering enabled, try to buffer a
2101 // valid sequence of a keyframe and a nonkeyframe: non-increasing presentation
2102 // timestamps are supported for audio nonkeyframes, so long as they don't
2103 // decrease. For sequence mode versions, timestampOffset is adjusted to make
2104 // it act like segments mode.
2105 InSequence s;
2106 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2107 if (use_sequence_mode_) {
2108 frame_processor_->SetSequenceMode(true);
2109 SetTimestampOffset(Milliseconds(100));
2110 }
2111
2112 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(110)));
2113 EXPECT_TRUE(ProcessFrames("100K", ""));
2114 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2115 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,110) }");
2116
2117 // Processing an audio nonkeyframe with same PTS as the previous frame should
2118 // succeed, though there is presentation interval overlap causing removal of
2119 // the previous frame (in this case, a keyframe), and hence the new dependent
2120 // nonkeyframe is not buffered.
2121 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(110)));
2122 EXPECT_TRUE(ProcessFrames("100|110", ""));
2123 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2124 CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
2125 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "");
2126 }
2127
TEST_P(FrameProcessorTest,NonkeyframeAudioBuffering_ValidSameNonKeyframePts_2)2128 TEST_P(FrameProcessorTest,
2129 NonkeyframeAudioBuffering_ValidSameNonKeyframePts_2) {
2130 // With the support for audio nonkeyframe buffering enabled, try to buffer a
2131 // valid sequence of nonkeyframes: non-increasing presentation timestamps are
2132 // supported for audio nonkeyframes, so long as they don't decrease. For
2133 // sequence mode versions, timestampOffset is adjusted to make it act like
2134 // segments mode.
2135 InSequence s;
2136 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2137 if (use_sequence_mode_) {
2138 frame_processor_->SetSequenceMode(true);
2139 SetTimestampOffset(Milliseconds(100));
2140 }
2141
2142 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(120)));
2143 EXPECT_TRUE(ProcessFrames("100K 110", ""));
2144 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2145 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,120) }");
2146
2147 // Processing an audio nonkeyframe with same PTS as the previous frame should
2148 // succeed, though there is presentation interval overlap causing removal of
2149 // the previous nonkeyframe, and hence the new dependent nonkeyframe is not
2150 // buffered.
2151 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(120)));
2152 EXPECT_TRUE(ProcessFrames("110|120", ""));
2153 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2154 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,110) }");
2155 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "100K");
2156 }
2157
TEST_P(FrameProcessorTest,NonkeyframeAudioBuffering_AppendWindowFilterDroppedPrerollKeyframe)2158 TEST_P(FrameProcessorTest,
2159 NonkeyframeAudioBuffering_AppendWindowFilterDroppedPrerollKeyframe) {
2160 // For simplicity currently, if the preroll (keyframe) buffer was entirely
2161 // prior to the append window and dropped, an approximately continuous
2162 // keyframe is still required to use that dropped frame as preroll (for
2163 // simplicity). This may change in future if append window trimming of
2164 // nonkeyframes with a fully excluded preroll keyframe is commonly needed to
2165 // be supported.
2166 InSequence s;
2167 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2168 if (use_sequence_mode_)
2169 frame_processor_->SetSequenceMode(true);
2170 SetTimestampOffset(Milliseconds(-10));
2171
2172 EXPECT_MEDIA_LOG(DroppedFrame("audio", -10000));
2173 if (use_sequence_mode_)
2174 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(-10)));
2175 else
2176 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(0)));
2177 EXPECT_TRUE(ProcessFrames("0K", ""));
2178
2179 // This nonkeyframe is dropped for simplicity since it depends on a preroll
2180 // keyframe which was entirely outside the append window.
2181 if (use_sequence_mode_)
2182 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(-10)));
2183 else
2184 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(0)));
2185 EXPECT_TRUE(ProcessFrames("10", ""));
2186
2187 // Only the following keyframe should buffer successfully, with no preroll.
2188 EXPECT_MEDIA_LOG(DroppedAppendWindowUnusedPreroll(-10000, -10000, 10000));
2189 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
2190 EXPECT_TRUE(ProcessFrames("20K", ""));
2191
2192 CheckExpectedRangesByTimestamp(audio_.get(), "{ [10,20) }");
2193 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "10:20K");
2194 }
2195
TEST_P(FrameProcessorTest,NonkeyframeAudioBuffering_AppendWindowFilter_TrimFront)2196 TEST_P(FrameProcessorTest,
2197 NonkeyframeAudioBuffering_AppendWindowFilter_TrimFront) {
2198 InSequence s;
2199 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2200 if (use_sequence_mode_)
2201 frame_processor_->SetSequenceMode(true);
2202 SetTimestampOffset(Milliseconds(-4));
2203 EXPECT_MEDIA_LOG(TruncatedFrame(-4000, 6000, "start", 0));
2204 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(26)));
2205 EXPECT_TRUE(ProcessFrames("0K 10 20", ""));
2206 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,26) }");
2207 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "0K 6:10N 16:20N");
2208 }
2209
TEST_P(FrameProcessorTest,NonkeyframeAudioBuffering_AppendWindowFilter_TrimEnd)2210 TEST_P(FrameProcessorTest,
2211 NonkeyframeAudioBuffering_AppendWindowFilter_TrimEnd) {
2212 InSequence s;
2213 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2214 if (use_sequence_mode_)
2215 frame_processor_->SetSequenceMode(true);
2216
2217 append_window_end_ = Milliseconds(26);
2218
2219 EXPECT_MEDIA_LOG(TruncatedFrame(20000, 30000, "end", 26000));
2220 EXPECT_MEDIA_LOG(DroppedFrameCheckAppendWindow("audio", 0, 26000));
2221 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(26)));
2222 EXPECT_TRUE(ProcessFrames("0K 10 20 30", ""));
2223 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,26) }");
2224 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "0K 10N 20N");
2225 }
2226
TEST_P(FrameProcessorTest,NonkeyframeAudioBuffering_TrimSpliceOverlap)2227 TEST_P(FrameProcessorTest, NonkeyframeAudioBuffering_TrimSpliceOverlap) {
2228 // White-box test which focuses on the behavior of underlying
2229 // SourceBufferStream::TrimSpliceOverlap() for frame sequences involving
2230 // nonkeyframes appended by the FrameProcessor. That method detects and
2231 // performs splice trimming on every audio frame following either a
2232 // discontinuity or the beginning of ProcessFrames(), and also on audio frames
2233 // with PTS not directly continuous with the highest frame end PTS already
2234 // processed. We vary |frame_duration_| in this test to avoid confusing
2235 // int:decimal pairs in the eventual CheckReads* call.
2236 InSequence s;
2237 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2238 if (use_sequence_mode_)
2239 frame_processor_->SetSequenceMode(true);
2240
2241 frame_duration_ = base::TimeDelta::FromMicroseconds(9750);
2242 EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
2243 EXPECT_TRUE(ProcessFrames("0K", ""));
2244
2245 // As with all-keyframe streams, a slight jump forward should not trigger any
2246 // splicing logic, though accumulations of these may result in loss of A/V
2247 // sync.
2248 frame_duration_ = base::TimeDelta::FromMicroseconds(10250);
2249 EXPECT_CALL(callbacks_,
2250 PossibleDurationIncrease(Milliseconds(10) + frame_duration_));
2251 EXPECT_TRUE(ProcessFrames("10", ""));
2252
2253 // As with all-keyframe streams, a slightly end-overlapping nonkeyframe should
2254 // not trigger any splicing logic, though accumulations of these may result in
2255 // loss of A/V sync. The difference here is there isn't even any emission of a
2256 // "too little splice overlap" media log, since the new frame is a
2257 // nonkeyframe.
2258 frame_duration_ = Milliseconds(10);
2259 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(30)));
2260 EXPECT_TRUE(ProcessFrames("20", ""));
2261
2262 // A heavily overlapping nonkeyframe should not trigger any splicing logic,
2263 // so long as it isn't completely discontinuous. This is unlike all-keyframe
2264 // audio streams, where such a heavy overlap would end-trim the overlapped
2265 // frame. Accumulations of these could rapidly lead to loss of A/V sync.
2266 // Nonkeyframe timestamp & duration metadata sequences need to be correctly
2267 // muxed to avoid this.
2268 frame_duration_ = base::TimeDelta::FromMicroseconds(10250);
2269 EXPECT_CALL(callbacks_,
2270 PossibleDurationIncrease(Milliseconds(22) + frame_duration_));
2271 EXPECT_TRUE(ProcessFrames("22", ""));
2272
2273 // A keyframe that end-overlaps a nonkeyframe will trigger splicing logic.
2274 // Here, we test a "too little splice overlap" case.
2275 frame_duration_ = Milliseconds(10);
2276 EXPECT_MEDIA_LOG(SkippingSpliceTooLittleOverlap(32000, 250));
2277 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(42)));
2278 EXPECT_TRUE(ProcessFrames("32K", ""));
2279
2280 // And a keyframe that significantly end-overlaps a nonkeyframe will trigger
2281 // splicing logic that can perform end-trimming of the overlapped frame.
2282 // First, we buffer another nonkeyframe.
2283 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(52)));
2284 EXPECT_TRUE(ProcessFrames("42", ""));
2285 // Verify correct splice behavior on significant overlap of the nonkeyframe by
2286 // a new keyframe.
2287 EXPECT_MEDIA_LOG(TrimmedSpliceOverlap(45000, 42000, 7000));
2288 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(55)));
2289 EXPECT_TRUE(ProcessFrames("45K", ""));
2290
2291 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,55) }");
2292 CheckReadsAndKeyframenessThenReadStalls(audio_.get(),
2293 "0K 10N 20N 22N 32K 42N 45K");
2294 }
2295
2296 INSTANTIATE_TEST_SUITE_P(SequenceMode, FrameProcessorTest, Values(true));
2297 INSTANTIATE_TEST_SUITE_P(SegmentsMode, FrameProcessorTest, Values(false));
2298
2299 } // namespace media
2300