1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
14 #include "base/bind.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"
31 using base::Milliseconds;
33 using ::testing::InSequence;
34 using ::testing::StrictMock;
35 using ::testing::Values;
39 // Helpers to encode/decode a base::TimeDelta to/from a string, used in these
40 // tests to populate coded frame payloads with an encoded version of the
41 // original frame timestamp while (slightly) obfuscating the payload itself to
42 // help ensure the payload itself is neither changed by frame processing nor
43 // interpreted directly and mistakenly as a base::TimeDelta by frame processing.
44 std::string EncodeTestPayload(base::TimeDelta timestamp) {
45 return base::NumberToString(timestamp.InMicroseconds());
48 base::TimeDelta DecodeTestPayload(std::string payload) {
49 int64_t microseconds = 0;
50 CHECK(base::StringToInt64(payload, µseconds));
51 return base::Microseconds(microseconds);
58 typedef StreamParser::BufferQueue BufferQueue;
59 typedef StreamParser::TrackId TrackId;
61 // Used for setting expectations on callbacks. Using a StrictMock also lets us
62 // test for missing or extra callbacks.
63 class FrameProcessorTestCallbackHelper {
65 FrameProcessorTestCallbackHelper() = default;
67 FrameProcessorTestCallbackHelper(const FrameProcessorTestCallbackHelper&) =
69 FrameProcessorTestCallbackHelper& operator=(
70 const FrameProcessorTestCallbackHelper&) = delete;
72 virtual ~FrameProcessorTestCallbackHelper() = default;
74 MOCK_METHOD1(OnParseWarning, void(const SourceBufferParseWarning));
75 MOCK_METHOD1(PossibleDurationIncrease, void(base::TimeDelta new_duration));
77 // Helper that calls the mock method as well as does basic sanity checks on
79 void OnPossibleDurationIncrease(base::TimeDelta new_duration) {
80 PossibleDurationIncrease(new_duration);
81 ASSERT_NE(kNoTimestamp, new_duration);
82 ASSERT_NE(kInfiniteDuration, new_duration);
85 MOCK_METHOD2(OnAppend,
86 void(const DemuxerStream::Type type,
87 const BufferQueue* buffers));
88 MOCK_METHOD3(OnGroupStart,
89 void(const DemuxerStream::Type type,
90 DecodeTimestamp start_dts,
91 base::TimeDelta start_pts));
94 class FrameProcessorTest : public ::testing::TestWithParam<bool> {
96 FrameProcessorTest(const FrameProcessorTest&) = delete;
97 FrameProcessorTest& operator=(const FrameProcessorTest&) = delete;
101 : append_window_end_(kInfiniteDuration),
102 frame_duration_(Milliseconds(10)),
105 use_sequence_mode_ = GetParam();
106 frame_processor_ = std::make_unique<FrameProcessor>(
108 &FrameProcessorTestCallbackHelper::OnPossibleDurationIncrease,
109 base::Unretained(&callbacks_)),
111 frame_processor_->SetParseWarningCallback(
112 base::BindRepeating(&FrameProcessorTestCallbackHelper::OnParseWarning,
113 base::Unretained(&callbacks_)));
119 OBSERVE_APPENDS_AND_GROUP_STARTS = 1 << 2,
120 USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES = 1 << 3
123 void AddTestTracks(int stream_flags) {
124 const bool has_audio = (stream_flags & HAS_AUDIO) != 0;
125 const bool has_video = (stream_flags & HAS_VIDEO) != 0;
126 ASSERT_TRUE(has_audio || has_video);
128 const bool setup_observers =
129 (stream_flags & OBSERVE_APPENDS_AND_GROUP_STARTS) != 0;
131 const bool support_audio_nonkeyframes =
132 (stream_flags & USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES) != 0;
133 ASSERT_TRUE(has_audio || !support_audio_nonkeyframes);
136 CreateAndConfigureStream(DemuxerStream::AUDIO, setup_observers,
137 support_audio_nonkeyframes);
139 EXPECT_TRUE(frame_processor_->AddTrack(audio_id_, audio_.get()));
140 SeekStream(audio_.get(), Milliseconds(0));
143 CreateAndConfigureStream(DemuxerStream::VIDEO, setup_observers, false);
145 EXPECT_TRUE(frame_processor_->AddTrack(video_id_, video_.get()));
146 SeekStream(video_.get(), Milliseconds(0));
150 void SetTimestampOffset(base::TimeDelta new_offset) {
151 timestamp_offset_ = new_offset;
152 frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset_);
155 base::TimeDelta MillisecondStringToTimestamp(std::string ts_string) {
156 if (ts_string == "Min") {
160 if (ts_string == "Max") {
161 return kInfiniteDuration;
164 // Handle large integers precisely without converting through a double.
165 if (ts_string.find('.') == std::string::npos) {
166 int64_t milliseconds;
167 CHECK(base::StringToInt64(ts_string, &milliseconds));
168 return Milliseconds(milliseconds);
172 CHECK(base::StringToDouble(ts_string, &ts_double));
173 return Milliseconds(ts_double);
176 BufferQueue StringToBufferQueue(const std::string& buffers_to_append,
177 const TrackId track_id,
178 const DemuxerStream::Type type) {
179 std::vector<std::string> timestamps = base::SplitString(
180 buffers_to_append, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
183 for (size_t i = 0; i < timestamps.size(); i++) {
184 bool is_keyframe = false;
185 if (base::EndsWith(timestamps[i], "K", base::CompareCase::SENSITIVE)) {
187 // Remove the "K" off of the token.
188 timestamps[i] = timestamps[i].substr(0, timestamps[i].length() - 1);
191 // Use custom decode timestamp if included.
192 std::vector<std::string> buffer_timestamps = base::SplitString(
193 timestamps[i], "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
194 if (buffer_timestamps.size() == 1)
195 buffer_timestamps.push_back(buffer_timestamps[0]);
196 CHECK_EQ(2u, buffer_timestamps.size());
198 const base::TimeDelta pts =
199 MillisecondStringToTimestamp(buffer_timestamps[0]);
200 const DecodeTimestamp dts = DecodeTimestamp::FromPresentationTime(
201 MillisecondStringToTimestamp(buffer_timestamps[1]));
203 // Create buffer. Encode the original pts as the buffer's data to enable
204 // later verification of possible buffer relocation in presentation
205 // timeline due to coded frame processing.
206 const std::string payload_string = EncodeTestPayload(pts);
207 const char* pts_as_cstr = payload_string.c_str();
208 scoped_refptr<StreamParserBuffer> buffer = StreamParserBuffer::CopyFrom(
209 reinterpret_cast<const uint8_t*>(pts_as_cstr), strlen(pts_as_cstr),
210 is_keyframe, type, track_id);
211 CHECK(DecodeTestPayload(
212 std::string(reinterpret_cast<const char*>(buffer->data()),
213 buffer->data_size())) == pts);
215 buffer->set_timestamp(pts);
216 if (DecodeTimestamp::FromPresentationTime(pts) != dts) {
217 buffer->SetDecodeTimestamp(dts);
220 buffer->set_duration(frame_duration_);
221 buffers.push_back(buffer);
226 bool ProcessFrames(const std::string& audio_timestamps,
227 const std::string& video_timestamps) {
228 StreamParser::BufferQueueMap buffer_queue_map;
229 const auto& audio_buffers =
230 StringToBufferQueue(audio_timestamps, audio_id_, DemuxerStream::AUDIO);
231 if (!audio_buffers.empty())
232 buffer_queue_map.insert(std::make_pair(audio_id_, audio_buffers));
233 const auto& video_buffers =
234 StringToBufferQueue(video_timestamps, video_id_, DemuxerStream::VIDEO);
235 if (!video_buffers.empty())
236 buffer_queue_map.insert(std::make_pair(video_id_, video_buffers));
237 return frame_processor_->ProcessFrames(
238 buffer_queue_map, append_window_start_, append_window_end_,
242 // Compares |expected| to the buffered ranges of |stream| formatted into a
243 // string as follows:
245 // If no ranges: "{ }"
246 // If one range: "{ [start1,end1) }"
247 // If multiple ranges, they are added space-delimited in sequence, like:
248 // "{ [start1,end1) [start2,end2) }"
250 // startN and endN are the respective buffered start and end times of the
251 // range in integer milliseconds.
252 void CheckExpectedRangesByTimestamp(ChunkDemuxerStream* stream,
253 const std::string& expected) {
254 // Note, DemuxerStream::TEXT streams return [0,duration (==infinity here))
255 Ranges<base::TimeDelta> r = stream->GetBufferedRanges(kInfiniteDuration);
257 std::stringstream ss;
259 for (size_t i = 0; i < r.size(); ++i) {
260 int64_t start = r.start(i).InMilliseconds();
261 int64_t end = r.end(i).InMilliseconds();
262 ss << "[" << start << "," << end << ") ";
265 EXPECT_EQ(expected, ss.str());
268 void CheckReadStalls(ChunkDemuxerStream* stream) {
272 read_callback_called_ = false;
273 stream->Read(base::BindOnce(&FrameProcessorTest::StoreStatusAndBuffer,
274 base::Unretained(this)));
275 base::RunLoop().RunUntilIdle();
276 } while (++loop_count < 2 && read_callback_called_ &&
277 last_read_status_ == DemuxerStream::kAborted);
279 ASSERT_FALSE(read_callback_called_ &&
280 last_read_status_ == DemuxerStream::kAborted)
281 << "2 kAborted reads in a row. Giving up.";
282 EXPECT_FALSE(read_callback_called_);
285 // Doesn't check keyframeness, but otherwise is the same as
286 // CheckReadsAndOptionallyKeyframenessThenReadStalls().
287 void CheckReadsThenReadStalls(ChunkDemuxerStream* stream,
288 const std::string& expected) {
289 CheckReadsAndOptionallyKeyframenessThenReadStalls(stream, expected, false);
292 // Checks keyframeness using
293 // CheckReadsAndOptionallyKeyframenessThenReadStalls().
294 void CheckReadsAndKeyframenessThenReadStalls(ChunkDemuxerStream* stream,
295 const std::string& expected) {
296 CheckReadsAndOptionallyKeyframenessThenReadStalls(stream, expected, true);
299 // Format of |expected| is a space-delimited sequence of
300 // timestamp_in_ms:original_timestamp_in_ms. original_timestamp_in_ms (and the
301 // colon) must be omitted if it is the same as timestamp_in_ms. If
302 // |check_keyframeness| is true, then each frame in |expected| must end with
303 // 'K' or 'N', which respectively must match the read result frames'
305 void CheckReadsAndOptionallyKeyframenessThenReadStalls(
306 ChunkDemuxerStream* stream,
307 const std::string& expected,
308 bool check_keyframeness) {
309 std::vector<std::string> timestamps = base::SplitString(
310 expected, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
311 std::stringstream ss;
312 for (size_t i = 0; i < timestamps.size(); ++i) {
316 read_callback_called_ = false;
317 stream->Read(base::BindOnce(&FrameProcessorTest::StoreStatusAndBuffer,
318 base::Unretained(this)));
319 base::RunLoop().RunUntilIdle();
320 EXPECT_TRUE(read_callback_called_);
321 } while (++loop_count < 2 &&
322 last_read_status_ == DemuxerStream::kAborted);
324 ASSERT_FALSE(last_read_status_ == DemuxerStream::kAborted)
325 << "2 kAborted reads in a row. Giving up.";
326 EXPECT_EQ(DemuxerStream::kOk, last_read_status_);
327 EXPECT_FALSE(last_read_buffer_->end_of_stream());
332 int time_in_ms = last_read_buffer_->timestamp().InMilliseconds();
335 // Decode the original_time_in_ms from the buffer's data.
336 double original_time_in_ms;
337 original_time_in_ms =
338 DecodeTestPayload(std::string(reinterpret_cast<const char*>(
339 last_read_buffer_->data()),
340 last_read_buffer_->data_size()))
342 if (original_time_in_ms != time_in_ms)
343 ss << ":" << original_time_in_ms;
345 // Detect full-discard preroll buffer.
346 if (last_read_buffer_->discard_padding().first == kInfiniteDuration &&
347 last_read_buffer_->discard_padding().second.is_zero()) {
351 // Conditionally check keyframeness.
352 if (check_keyframeness) {
353 if (last_read_buffer_->is_key_frame())
360 EXPECT_EQ(expected, ss.str());
361 CheckReadStalls(stream);
364 // TODO(wolenetz): Refactor to instead verify the expected signalling or lack
365 // thereof of new coded frame group by the FrameProcessor. See
366 // https://crbug.com/580613.
367 bool in_coded_frame_group() {
368 return !frame_processor_->pending_notify_all_group_start_;
371 void SeekStream(ChunkDemuxerStream* stream, base::TimeDelta seek_time) {
372 stream->AbortReads();
373 stream->Seek(seek_time);
374 stream->StartReturningData();
377 base::test::SingleThreadTaskEnvironment task_environment_;
378 StrictMock<MockMediaLog> media_log_;
379 StrictMock<FrameProcessorTestCallbackHelper> callbacks_;
381 bool use_sequence_mode_;
383 std::unique_ptr<FrameProcessor> frame_processor_;
384 base::TimeDelta append_window_start_;
385 base::TimeDelta append_window_end_;
386 base::TimeDelta timestamp_offset_;
387 base::TimeDelta frame_duration_;
388 std::unique_ptr<ChunkDemuxerStream> audio_;
389 std::unique_ptr<ChunkDemuxerStream> video_;
390 const TrackId audio_id_;
391 const TrackId video_id_;
392 const BufferQueue empty_queue_;
394 // StoreStatusAndBuffer's most recent result.
395 DemuxerStream::Status last_read_status_;
396 scoped_refptr<DecoderBuffer> last_read_buffer_;
397 bool read_callback_called_;
400 void StoreStatusAndBuffer(DemuxerStream::Status status,
401 scoped_refptr<DecoderBuffer> buffer) {
402 if (status == DemuxerStream::kOk && buffer.get()) {
403 DVLOG(3) << __func__ << "status: " << status
404 << " ts: " << buffer->timestamp().InSecondsF();
406 DVLOG(3) << __func__ << "status: " << status << " ts: n/a";
409 read_callback_called_ = true;
410 last_read_status_ = status;
411 last_read_buffer_ = buffer;
414 void CreateAndConfigureStream(DemuxerStream::Type type,
415 bool setup_observers,
416 bool support_audio_nonkeyframes) {
417 // TODO(wolenetz/dalecurtis): Also test with splicing disabled?
419 ChunkDemuxerStream* stream;
421 case DemuxerStream::AUDIO: {
422 ASSERT_FALSE(audio_);
423 audio_ = std::make_unique<ChunkDemuxerStream>(DemuxerStream::AUDIO,
424 MediaTrack::Id("1"));
425 AudioDecoderConfig decoder_config;
426 if (support_audio_nonkeyframes) {
427 decoder_config = AudioDecoderConfig(
428 AudioCodec::kAAC, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO,
429 1000, EmptyExtraData(), EncryptionScheme::kUnencrypted);
430 decoder_config.set_profile(AudioCodecProfile::kXHE_AAC);
433 AudioDecoderConfig(AudioCodec::kVorbis, kSampleFormatPlanarF32,
434 CHANNEL_LAYOUT_STEREO, 1000, EmptyExtraData(),
435 EncryptionScheme::kUnencrypted);
437 frame_processor_->OnPossibleAudioConfigUpdate(decoder_config);
439 audio_->UpdateAudioConfig(decoder_config, false, &media_log_));
441 stream = audio_.get();
444 case DemuxerStream::VIDEO: {
445 ASSERT_FALSE(video_);
446 ASSERT_FALSE(support_audio_nonkeyframes);
447 video_ = std::make_unique<ChunkDemuxerStream>(DemuxerStream::VIDEO,
448 MediaTrack::Id("2"));
449 ASSERT_TRUE(video_->UpdateVideoConfig(TestVideoConfig::Normal(), false,
451 stream = video_.get();
454 // TODO(wolenetz): Test text coded frame processing.
455 case DemuxerStream::TEXT:
456 case DemuxerStream::UNKNOWN: {
461 if (setup_observers) {
462 stream->set_append_observer_for_testing(
463 base::BindRepeating(&FrameProcessorTestCallbackHelper::OnAppend,
464 base::Unretained(&callbacks_), type));
465 stream->set_group_start_observer_for_testing(
466 base::BindRepeating(&FrameProcessorTestCallbackHelper::OnGroupStart,
467 base::Unretained(&callbacks_), type));
472 TEST_P(FrameProcessorTest, WrongTypeInAppendedBuffer) {
473 AddTestTracks(HAS_AUDIO);
474 EXPECT_FALSE(in_coded_frame_group());
476 StreamParser::BufferQueueMap buffer_queue_map;
477 const auto& audio_buffers =
478 StringToBufferQueue("0K", audio_id_, DemuxerStream::VIDEO);
479 buffer_queue_map.insert(std::make_pair(audio_id_, audio_buffers));
480 EXPECT_MEDIA_LOG(FrameTypeMismatchesTrackType("video", "1"));
482 frame_processor_->ProcessFrames(buffer_queue_map, append_window_start_,
483 append_window_end_, ×tamp_offset_));
484 EXPECT_FALSE(in_coded_frame_group());
485 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
486 CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
487 CheckReadStalls(audio_.get());
490 TEST_P(FrameProcessorTest, NonMonotonicallyIncreasingTimestampInOneCall) {
491 AddTestTracks(HAS_AUDIO);
493 EXPECT_MEDIA_LOG(ParsedBuffersNotInDTSSequence());
494 EXPECT_FALSE(ProcessFrames("10K 0K", ""));
495 EXPECT_FALSE(in_coded_frame_group());
496 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
497 CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
498 CheckReadStalls(audio_.get());
501 TEST_P(FrameProcessorTest, AudioOnly_SingleFrame) {
502 // Tests A: P(A) -> (a)
504 AddTestTracks(HAS_AUDIO);
505 if (use_sequence_mode_)
506 frame_processor_->SetSequenceMode(true);
508 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
509 EXPECT_TRUE(ProcessFrames("0K", ""));
510 EXPECT_TRUE(in_coded_frame_group());
511 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
512 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) }");
513 CheckReadsThenReadStalls(audio_.get(), "0");
516 TEST_P(FrameProcessorTest, VideoOnly_SingleFrame) {
517 // Tests V: P(V) -> (v)
519 AddTestTracks(HAS_VIDEO);
520 if (use_sequence_mode_)
521 frame_processor_->SetSequenceMode(true);
523 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
524 EXPECT_TRUE(ProcessFrames("", "0K"));
525 EXPECT_TRUE(in_coded_frame_group());
526 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
527 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,10) }");
528 CheckReadsThenReadStalls(video_.get(), "0");
531 TEST_P(FrameProcessorTest, AudioOnly_TwoFrames) {
532 // Tests A: P(A0, A10) -> (a0, a10)
534 AddTestTracks(HAS_AUDIO);
535 if (use_sequence_mode_)
536 frame_processor_->SetSequenceMode(true);
538 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
539 EXPECT_TRUE(ProcessFrames("0K 10K", ""));
540 EXPECT_TRUE(in_coded_frame_group());
541 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
542 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
543 CheckReadsThenReadStalls(audio_.get(), "0 10");
546 TEST_P(FrameProcessorTest, AudioOnly_SetOffsetThenSingleFrame) {
547 // Tests A: STSO(50)+P(A0) -> TSO==50,(a0@50)
549 AddTestTracks(HAS_AUDIO);
550 if (use_sequence_mode_)
551 frame_processor_->SetSequenceMode(true);
553 SetTimestampOffset(Milliseconds(50));
554 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
555 EXPECT_TRUE(ProcessFrames("0K", ""));
556 EXPECT_TRUE(in_coded_frame_group());
557 EXPECT_EQ(Milliseconds(50), timestamp_offset_);
558 CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) }");
560 // We do not stall on reading without seeking to 50ms due to
561 // SourceBufferStream::kSeekToStartFudgeRoom().
562 CheckReadsThenReadStalls(audio_.get(), "50:0");
565 TEST_P(FrameProcessorTest, AudioOnly_SetOffsetThenFrameTimestampBelowOffset) {
566 // Tests A: STSO(50)+P(A20) ->
567 // if sequence mode: TSO==30,(a20@50)
568 // if segments mode: TSO==50,(a20@70)
570 AddTestTracks(HAS_AUDIO);
571 if (use_sequence_mode_)
572 frame_processor_->SetSequenceMode(true);
574 SetTimestampOffset(Milliseconds(50));
576 if (use_sequence_mode_) {
577 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
579 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(80)));
582 EXPECT_TRUE(ProcessFrames("20K", ""));
583 EXPECT_TRUE(in_coded_frame_group());
585 // We do not stall on reading without seeking to 50ms / 70ms due to
586 // SourceBufferStream::kSeekToStartFudgeRoom().
587 if (use_sequence_mode_) {
588 EXPECT_EQ(Milliseconds(30), timestamp_offset_);
589 CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) }");
590 CheckReadsThenReadStalls(audio_.get(), "50:20");
592 EXPECT_EQ(Milliseconds(50), timestamp_offset_);
593 CheckExpectedRangesByTimestamp(audio_.get(), "{ [70,80) }");
594 CheckReadsThenReadStalls(audio_.get(), "70:20");
598 TEST_P(FrameProcessorTest, AudioOnly_SequentialProcessFrames) {
599 // Tests A: P(A0,A10)+P(A20,A30) -> (a0,a10,a20,a30)
601 AddTestTracks(HAS_AUDIO);
602 if (use_sequence_mode_)
603 frame_processor_->SetSequenceMode(true);
605 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
606 EXPECT_TRUE(ProcessFrames("0K 10K", ""));
607 EXPECT_TRUE(in_coded_frame_group());
608 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
609 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
611 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
612 EXPECT_TRUE(ProcessFrames("20K 30K", ""));
613 EXPECT_TRUE(in_coded_frame_group());
614 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
615 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
617 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
620 TEST_P(FrameProcessorTest, AudioOnly_NonSequentialProcessFrames) {
621 // Tests A: P(A20,A30)+P(A0,A10) ->
622 // if sequence mode: TSO==-20 after first P(), 20 after second P(), and
623 // a(20@0,a30@10,a0@20,a10@30)
624 // if segments mode: TSO==0,(a0,a10,a20,a30)
626 AddTestTracks(HAS_AUDIO);
627 if (use_sequence_mode_) {
628 frame_processor_->SetSequenceMode(true);
629 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
631 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
634 EXPECT_TRUE(ProcessFrames("20K 30K", ""));
635 EXPECT_TRUE(in_coded_frame_group());
637 if (use_sequence_mode_) {
638 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
639 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
640 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
642 CheckExpectedRangesByTimestamp(audio_.get(), "{ [20,40) }");
643 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
644 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
647 EXPECT_TRUE(ProcessFrames("0K 10K", ""));
648 EXPECT_TRUE(in_coded_frame_group());
650 if (use_sequence_mode_) {
651 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
652 EXPECT_EQ(Milliseconds(20), timestamp_offset_);
653 CheckReadsThenReadStalls(audio_.get(), "0:20 10:30 20:0 30:10");
655 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
656 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
657 // Re-seek to 0ms now that we've appended data earlier than what has already
658 // satisfied our initial seek to start, above.
659 SeekStream(audio_.get(), Milliseconds(0));
660 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
664 TEST_P(FrameProcessorTest, AudioVideo_SequentialProcessFrames) {
665 // Tests AV: P(A0,A10;V0k,V10,V20)+P(A20,A30,A40,V30) ->
666 // (a0,a10,a20,a30,a40);(v0,v10,v20,v30)
668 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
669 if (use_sequence_mode_) {
670 frame_processor_->SetSequenceMode(true);
671 EXPECT_CALL(callbacks_,
672 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
673 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
676 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(30)));
677 EXPECT_TRUE(ProcessFrames("0K 10K", "0K 10 20"));
678 EXPECT_TRUE(in_coded_frame_group());
679 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
680 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
681 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,30) }");
683 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(50)));
684 EXPECT_TRUE(ProcessFrames("20K 30K 40K", "30"));
685 EXPECT_TRUE(in_coded_frame_group());
686 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
687 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,50) }");
688 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,40) }");
690 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30 40");
691 CheckReadsThenReadStalls(video_.get(), "0 10 20 30");
694 TEST_P(FrameProcessorTest, AudioVideo_Discontinuity) {
695 // Tests AV: P(A0,A10,A30,A40,A50;V0key,V10,V40,V50key) ->
696 // if sequence mode: TSO==10,(a0,a10,a30,a40,a50@60);(v0,v10,v50@60)
697 // if segments mode: TSO==0,(a0,a10,a30,a40,a50);(v0,v10,v50)
698 // This assumes A40K is processed before V40, which depends currently on
699 // MergeBufferQueues() behavior.
701 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
702 if (use_sequence_mode_) {
703 frame_processor_->SetSequenceMode(true);
704 EXPECT_CALL(callbacks_,
705 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
706 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
707 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(70)));
709 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
712 EXPECT_TRUE(ProcessFrames("0K 10K 30K 40K 50K", "0K 10 40 50K"));
713 EXPECT_TRUE(in_coded_frame_group());
715 if (use_sequence_mode_) {
716 EXPECT_EQ(Milliseconds(10), timestamp_offset_);
717 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,70) }");
718 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,20) [60,70) }");
719 CheckReadsThenReadStalls(audio_.get(), "0 10 30 40 60:50");
720 CheckReadsThenReadStalls(video_.get(), "0 10");
721 SeekStream(video_.get(), Milliseconds(60));
722 CheckReadsThenReadStalls(video_.get(), "60:50");
724 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
725 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,60) }");
726 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,20) [50,60) }");
727 CheckReadsThenReadStalls(audio_.get(), "0 10 30 40 50");
728 CheckReadsThenReadStalls(video_.get(), "0 10");
729 SeekStream(video_.get(), Milliseconds(50));
730 CheckReadsThenReadStalls(video_.get(), "50");
734 TEST_P(FrameProcessorTest, AudioVideo_Discontinuity_TimestampOffset) {
736 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
737 frame_processor_->SetSequenceMode(use_sequence_mode_);
738 if (use_sequence_mode_) {
739 EXPECT_CALL(callbacks_,
740 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
741 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
744 // Start a coded frame group at time 100ms. Note the jagged start still uses
745 // the coded frame group's start time as the range start for both streams.
746 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
747 SetTimestampOffset(Milliseconds(100));
748 EXPECT_TRUE(ProcessFrames("0K 10K 20K", "10K 20K 30K"));
749 EXPECT_EQ(Milliseconds(100), timestamp_offset_);
750 EXPECT_TRUE(in_coded_frame_group());
751 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
752 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) }");
754 // Test the behavior of both 'sequence' and 'segments' mode if the coded frame
755 // sequence jumps forward beyond the normal discontinuity threshold.
756 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(240)));
757 SetTimestampOffset(Milliseconds(200));
758 EXPECT_TRUE(ProcessFrames("0K 10K 20K", "10K 20K 30K"));
759 EXPECT_EQ(Milliseconds(200), timestamp_offset_);
760 EXPECT_TRUE(in_coded_frame_group());
761 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) [200,230) }");
762 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [200,240) }");
764 // Test the behavior when timestampOffset adjustment causes next frames to be
765 // in the past relative to the previously processed frame and triggers a new
766 // coded frame group.
767 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(95)));
768 SetTimestampOffset(Milliseconds(55));
769 EXPECT_TRUE(ProcessFrames("0K 10K 20K", "10K 20K 30K"));
770 EXPECT_EQ(Milliseconds(55), timestamp_offset_);
771 EXPECT_TRUE(in_coded_frame_group());
772 // The new audio range is not within SourceBufferStream's coalescing threshold
773 // relative to the next range, but the new video range is within the
775 CheckExpectedRangesByTimestamp(audio_.get(),
776 "{ [55,85) [100,130) [200,230) }");
777 // Note that the range adjacency logic used in this case considers
778 // DTS 85 to be close enough to [100,140), even though the first DTS in video
779 // range [100,140) is actually 110. The muxed data started a coded frame
780 // group at time 100, informing the adjacency logic.
781 CheckExpectedRangesByTimestamp(video_.get(), "{ [55,140) [200,240) }");
783 // Verify the buffers.
784 // Re-seek now that we've appended data earlier than what already satisfied
785 // our initial seek to start.
786 SeekStream(audio_.get(), Milliseconds(55));
787 CheckReadsThenReadStalls(audio_.get(), "55:0 65:10 75:20");
788 SeekStream(audio_.get(), Milliseconds(100));
789 CheckReadsThenReadStalls(audio_.get(), "100:0 110:10 120:20");
790 SeekStream(audio_.get(), Milliseconds(200));
791 CheckReadsThenReadStalls(audio_.get(), "200:0 210:10 220:20");
793 SeekStream(video_.get(), Milliseconds(55));
794 CheckReadsThenReadStalls(video_.get(),
795 "65:10 75:20 85:30 110:10 120:20 130:30");
796 SeekStream(video_.get(), Milliseconds(200));
797 CheckReadsThenReadStalls(video_.get(), "210:10 220:20 230:30");
800 TEST_P(FrameProcessorTest, AudioVideo_OutOfSequence_After_Discontinuity) {
801 // Once a discontinuity is detected (and all tracks drop everything until the
802 // next keyframe per each track), we should gracefully handle the case where
803 // some tracks' first keyframe after the discontinuity are appended after, but
804 // end up earlier in timeline than some other track(s). In particular, we
805 // shouldn't notify all tracks that a new coded frame group is starting and
806 // begin dropping leading non-keyframes from all tracks. Rather, we should
807 // notify just the track encountering this new type of discontinuity. Since
808 // MSE doesn't require all media segments to contain media from every track,
809 // these append sequences can occur.
811 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
812 frame_processor_->SetSequenceMode(use_sequence_mode_);
814 // Begin with a simple set of appends for all tracks.
815 if (use_sequence_mode_) {
816 // Allow room in the timeline for the last audio append (50K, below) in this
817 // test to remain within default append window [0, +Infinity]. Moving the
818 // sequence mode appends to begin at time 100ms, the same time as the first
819 // append, below, results in a -20ms offset (instead of a -120ms offset)
820 // applied to frames beginning at the first frame after the discontinuity
821 // caused by the video append at 160K, below.
822 SetTimestampOffset(Milliseconds(100));
823 EXPECT_CALL(callbacks_,
824 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
825 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
827 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
828 EXPECT_TRUE(ProcessFrames("100K 110K 120K", "110K 120K 130K"));
829 EXPECT_TRUE(in_coded_frame_group());
830 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
831 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
832 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) }");
834 // Trigger (normal) discontinuity with one track (video).
835 if (use_sequence_mode_)
836 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(150)));
838 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(170)));
840 EXPECT_TRUE(ProcessFrames("", "160K"));
841 EXPECT_TRUE(in_coded_frame_group());
843 if (use_sequence_mode_) {
844 // The new video buffer is relocated into [140,150).
845 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
846 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
847 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,150) }");
849 // The new video buffer is at [160,170).
850 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
851 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
852 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [160,170) }");
855 // Append to the other track (audio) with lower time than the video frame we
856 // just appended. Append with a timestamp such that segments mode demonstrates
857 // we don't retroactively extend the new video buffer appended above's range
858 // start back to this audio start time.
859 if (use_sequence_mode_)
860 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(150)));
862 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(170)));
864 EXPECT_TRUE(ProcessFrames("50K", ""));
865 EXPECT_TRUE(in_coded_frame_group());
867 // Because this is the first audio buffer appended following the discontinuity
868 // detected while appending the video frame, above, a new coded frame group
869 // for video is not triggered.
870 if (use_sequence_mode_) {
871 // The new audio buffer is relocated into [30,40). Note the muxed 'sequence'
872 // mode append mode results in a buffered range gap in this case.
873 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
874 CheckExpectedRangesByTimestamp(audio_.get(), "{ [30,40) [100,130) }");
875 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,150) }");
877 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
878 CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) [100,130) }");
879 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [160,170) }");
882 // Finally, append a non-keyframe to the first track (video), to continue the
883 // GOP that started the normal discontinuity on the previous video append.
884 if (use_sequence_mode_)
885 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(160)));
887 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(180)));
889 EXPECT_TRUE(ProcessFrames("", "170"));
890 EXPECT_TRUE(in_coded_frame_group());
892 // Verify the final buffers. First, re-seek audio since we appended data
893 // earlier than what already satisfied our initial seek to start. We satisfy
894 // the seek with the first buffer in [0,1000).
895 SeekStream(audio_.get(), Milliseconds(0));
896 if (use_sequence_mode_) {
897 // The new video buffer is relocated into [150,160).
898 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
899 CheckExpectedRangesByTimestamp(audio_.get(), "{ [30,40) [100,130) }");
900 CheckReadsThenReadStalls(audio_.get(), "30:50");
901 SeekStream(audio_.get(), Milliseconds(100));
902 CheckReadsThenReadStalls(audio_.get(), "100 110 120");
904 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,160) }");
905 CheckReadsThenReadStalls(video_.get(), "110 120 130 140:160 150:170");
907 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
908 CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) [100,130) }");
909 CheckReadsThenReadStalls(audio_.get(), "50");
910 SeekStream(audio_.get(), Milliseconds(100));
911 CheckReadsThenReadStalls(audio_.get(), "100 110 120");
913 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [160,180) }");
914 CheckReadsThenReadStalls(video_.get(), "110 120 130");
915 SeekStream(video_.get(), Milliseconds(160));
916 CheckReadsThenReadStalls(video_.get(), "160 170");
920 TEST_P(FrameProcessorTest,
921 AppendWindowFilterOfNegativeBufferTimestampsWithPrerollDiscard) {
923 AddTestTracks(HAS_AUDIO);
924 if (use_sequence_mode_)
925 frame_processor_->SetSequenceMode(true);
927 SetTimestampOffset(Milliseconds(-20));
928 EXPECT_MEDIA_LOG(DroppedFrame("audio", -20000));
929 EXPECT_MEDIA_LOG(DroppedFrame("audio", -10000));
930 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
931 EXPECT_TRUE(ProcessFrames("0K 10K 20K", ""));
932 EXPECT_TRUE(in_coded_frame_group());
933 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
934 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) }");
935 CheckReadsThenReadStalls(audio_.get(), "0:10P 0:20");
938 TEST_P(FrameProcessorTest, AppendWindowFilterWithInexactPreroll) {
940 AddTestTracks(HAS_AUDIO);
941 if (use_sequence_mode_)
942 frame_processor_->SetSequenceMode(true);
943 SetTimestampOffset(Milliseconds(-10));
944 EXPECT_MEDIA_LOG(DroppedFrame("audio", -10000));
945 EXPECT_MEDIA_LOG(TruncatedFrame(-250, 9750, "start", 0));
946 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
947 EXPECT_TRUE(ProcessFrames("0K 9.75K 20K", ""));
948 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
949 CheckReadsThenReadStalls(audio_.get(), "0P 0:9.75 10:20");
952 TEST_P(FrameProcessorTest, AppendWindowFilterWithInexactPreroll_2) {
954 AddTestTracks(HAS_AUDIO);
955 if (use_sequence_mode_)
956 frame_processor_->SetSequenceMode(true);
957 SetTimestampOffset(Milliseconds(-10));
959 EXPECT_MEDIA_LOG(DroppedFrame("audio", -10000));
960 // Splice trimming checks are done on every audio frame following either a
961 // discontinuity or the beginning of ProcessFrames(), and are also done on
962 // audio frames with PTS not directly continuous with the highest frame end
963 // PTS already processed.
964 if (use_sequence_mode_)
965 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(-10)));
967 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(0)));
968 EXPECT_TRUE(ProcessFrames("0K", ""));
970 EXPECT_CALL(callbacks_, PossibleDurationIncrease(base::Microseconds(10250)));
971 EXPECT_TRUE(ProcessFrames("10.25K", ""));
973 EXPECT_MEDIA_LOG(SkippingSpliceTooLittleOverlap(10000, 250));
974 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
975 EXPECT_TRUE(ProcessFrames("20K", ""));
977 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
978 CheckReadsThenReadStalls(audio_.get(), "0P 0:10.25 10:20");
981 TEST_P(FrameProcessorTest, AllowNegativeFramePTSAndDTSBeforeOffsetAdjustment) {
983 AddTestTracks(HAS_AUDIO);
984 if (use_sequence_mode_) {
985 frame_processor_->SetSequenceMode(true);
986 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(30)));
988 EXPECT_MEDIA_LOG(TruncatedFrame(-5000, 5000, "start", 0));
989 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(25)));
992 EXPECT_TRUE(ProcessFrames("-5K 5K 15K", ""));
994 if (use_sequence_mode_) {
995 EXPECT_EQ(Milliseconds(5), timestamp_offset_);
996 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,30) }");
997 CheckReadsThenReadStalls(audio_.get(), "0:-5 10:5 20:15");
999 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1000 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,25) }");
1001 CheckReadsThenReadStalls(audio_.get(), "0:-5 5 15");
1005 TEST_P(FrameProcessorTest, PartialAppendWindowFilterNoDiscontinuity) {
1006 // Tests that spurious discontinuity is not introduced by a partially
1008 append_window_start_ = Milliseconds(7);
1011 AddTestTracks(HAS_AUDIO);
1012 if (use_sequence_mode_)
1013 frame_processor_->SetSequenceMode(true);
1014 EXPECT_MEDIA_LOG(TruncatedFrame(0, 10000, "start", 7000));
1015 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(29)));
1017 EXPECT_TRUE(ProcessFrames("0K 19K", ""));
1019 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1020 CheckExpectedRangesByTimestamp(audio_.get(), "{ [7,29) }");
1021 CheckReadsThenReadStalls(audio_.get(), "7:0 19");
1024 TEST_P(FrameProcessorTest,
1025 PartialAppendWindowFilterNoDiscontinuity_DtsAfterPts) {
1026 // Tests that spurious discontinuity is not introduced by a partially trimmed
1027 // frame that originally had DTS > PTS.
1029 AddTestTracks(HAS_AUDIO);
1031 if (use_sequence_mode_) {
1032 frame_processor_->SetSequenceMode(true);
1033 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
1035 EXPECT_MEDIA_LOG(TruncatedFrame(-7000, 3000, "start", 0));
1036 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(13)));
1039 // Process a sequence of two audio frames:
1040 // A: PTS -7ms, DTS 10ms, duration 10ms, keyframe
1041 // B: PTS 3ms, DTS 20ms, duration 10ms, keyframe
1042 EXPECT_TRUE(ProcessFrames("-7|10K 3|20K", ""));
1044 if (use_sequence_mode_) {
1045 // Sequence mode detected that frame A needs to be relocated 7ms into the
1046 // future to begin the sequence at time 0. There is no append window
1047 // filtering because the PTS result of the relocation is within the append
1048 // window of [0,+Infinity).
1049 // Frame A is relocated by 7 to PTS 0, DTS 17, duration 10.
1050 // Frame B is relocated by 7 to PTS 10, DTS 27, duration 10.
1051 EXPECT_EQ(Milliseconds(7), timestamp_offset_);
1053 // Start of frame A (0) through end of frame B (10+10).
1054 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
1056 // Frame A is now at PTS 0 (originally at PTS -7)
1057 // Frame B is now at PTS 10 (originally at PTS 3)
1058 CheckReadsThenReadStalls(audio_.get(), "0:-7 10:3");
1060 // Segments mode does not update timestampOffset automatically, so it
1061 // remained 0 and neither frame was relocated by timestampOffset.
1062 // Frame A's start *was* relocated by append window partial audio cropping:
1063 // Append window filtering (done by PTS, regardless of range buffering API)
1064 // did a partial crop of the first 7ms of frame A which was before
1065 // the default append window start time 0, and moved both the PTS and DTS of
1066 // frame A forward by 7 and reduced its duration by 7. Frame B was fully
1067 // inside the append window and remained uncropped and unrelocated.
1068 // Frame A is buffered at PTS -7+7=0, DTS 10+7=17, duration 10-7=3.
1069 // Frame B is buffered at PTS 3, DTS 20, duration 10.
1070 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1072 // Start of frame A (0) through end of frame B (3+10).
1073 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,13) }");
1075 // Frame A is now at PTS 0 (originally at PTS -7)
1076 // Frame B is now at PTS 3 (same as it was originally)
1077 CheckReadsThenReadStalls(audio_.get(), "0:-7 3");
1081 TEST_P(FrameProcessorTest, PartialAppendWindowFilterNoNewMediaSegment) {
1082 // Tests that a new media segment is not forcibly signalled for audio frame
1083 // partial front trim, to prevent incorrect introduction of a discontinuity
1084 // and potentially a non-keyframe video frame to be processed next after the
1087 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
1088 frame_processor_->SetSequenceMode(use_sequence_mode_);
1089 if (use_sequence_mode_) {
1090 EXPECT_CALL(callbacks_,
1091 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
1092 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
1094 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1095 EXPECT_TRUE(ProcessFrames("", "0K"));
1096 EXPECT_MEDIA_LOG(TruncatedFrame(-5000, 5000, "start", 0));
1097 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1098 EXPECT_TRUE(ProcessFrames("-5K", ""));
1099 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
1100 EXPECT_TRUE(ProcessFrames("", "10"));
1102 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1103 EXPECT_TRUE(in_coded_frame_group());
1104 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,5) }");
1105 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,20) }");
1106 CheckReadsThenReadStalls(audio_.get(), "0:-5");
1107 CheckReadsThenReadStalls(video_.get(), "0 10");
1110 TEST_P(FrameProcessorTest, AudioOnly_SequenceModeContinuityAcrossReset) {
1111 if (!use_sequence_mode_) {
1112 DVLOG(1) << "Skipping segments mode variant; inapplicable to this case.";
1117 AddTestTracks(HAS_AUDIO);
1118 frame_processor_->SetSequenceMode(true);
1119 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1120 EXPECT_TRUE(ProcessFrames("0K", ""));
1121 frame_processor_->Reset();
1122 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
1123 EXPECT_TRUE(ProcessFrames("100K", ""));
1125 EXPECT_EQ(Milliseconds(-90), timestamp_offset_);
1126 EXPECT_TRUE(in_coded_frame_group());
1127 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
1128 CheckReadsThenReadStalls(audio_.get(), "0 10:100");
1131 TEST_P(FrameProcessorTest, PartialAppendWindowZeroDurationPreroll) {
1133 AddTestTracks(HAS_AUDIO);
1134 frame_processor_->SetSequenceMode(use_sequence_mode_);
1136 append_window_start_ = Milliseconds(5);
1138 EXPECT_MEDIA_LOG(DroppedFrame("audio", use_sequence_mode_ ? 0 : 4000));
1139 // Append a 0 duration frame that falls just before the append window.
1140 frame_duration_ = Milliseconds(0);
1141 EXPECT_FALSE(in_coded_frame_group());
1142 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(0)));
1143 EXPECT_TRUE(ProcessFrames("4K", ""));
1144 // Verify buffer is not part of ranges. It should be silently saved for
1145 // preroll for future append.
1146 CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
1147 CheckReadsThenReadStalls(audio_.get(), "");
1148 EXPECT_FALSE(in_coded_frame_group());
1150 // Abort the reads from last stall. We don't want those reads to "complete"
1151 // when we append below. We will initiate new reads to confirm the buffer
1152 // looks as we expect.
1153 SeekStream(audio_.get(), Milliseconds(0));
1155 if (use_sequence_mode_) {
1156 EXPECT_MEDIA_LOG(TruncatedFrame(0, 10000, "start", 5000));
1158 EXPECT_MEDIA_LOG(TruncatedFrame(4000, 14000, "start", 5000));
1160 // Append a frame with 10ms duration, with 9ms falling after the window start.
1161 EXPECT_CALL(callbacks_, PossibleDurationIncrease(
1162 Milliseconds(use_sequence_mode_ ? 10 : 14)));
1163 frame_duration_ = Milliseconds(10);
1164 EXPECT_TRUE(ProcessFrames("4K", ""));
1165 EXPECT_TRUE(in_coded_frame_group());
1167 // Verify range updated to reflect last append was processed and trimmed, and
1168 // also that zero duration buffer was saved and attached as preroll.
1169 if (use_sequence_mode_) {
1170 // For sequence mode, append window trimming is applied after the append
1171 // is adjusted for timestampOffset. Basically, everything gets rebased to 0
1172 // and trimming then removes 5 seconds from the front.
1173 CheckExpectedRangesByTimestamp(audio_.get(), "{ [5,10) }");
1174 CheckReadsThenReadStalls(audio_.get(), "5:4P 5:4");
1175 } else { // segments mode
1176 CheckExpectedRangesByTimestamp(audio_.get(), "{ [5,14) }");
1177 CheckReadsThenReadStalls(audio_.get(), "5:4P 5:4");
1180 // Verify the preroll buffer still has zero duration.
1181 StreamParserBuffer* last_read_parser_buffer =
1182 static_cast<StreamParserBuffer*>(last_read_buffer_.get());
1183 ASSERT_EQ(Milliseconds(0),
1184 last_read_parser_buffer->preroll_buffer()->duration());
1187 TEST_P(FrameProcessorTest,
1188 OOOKeyframePrecededByDependantNonKeyframeShouldWarn) {
1190 AddTestTracks(HAS_VIDEO);
1191 frame_processor_->SetSequenceMode(use_sequence_mode_);
1193 if (use_sequence_mode_) {
1194 // Allow room in the timeline for the last video append (40|70, below) in
1195 // this test to remain within default append window [0, +Infinity]. Moving
1196 // the sequence mode appends to begin at time 50ms, the same time as the
1197 // first append, below, also results in identical expectation checks for
1198 // buffered ranges and buffer reads for both segments and sequence modes.
1199 SetTimestampOffset(Milliseconds(50));
1202 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(70)));
1203 EXPECT_TRUE(ProcessFrames("", "50K 60"));
1205 CheckExpectedRangesByTimestamp(video_.get(), "{ [50,70) }");
1207 EXPECT_CALL(callbacks_,
1209 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1210 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.05", "0.04"));
1211 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(70)));
1212 EXPECT_TRUE(ProcessFrames("", "40|70")); // PTS=40, DTS=70
1214 // This reflects the expectation that PTS start is not "pulled backward" for
1215 // the new frame at PTS=40 because current spec doesn't support SAP Type 2; it
1216 // has no steps in the coded frame processing algorithm that would do that
1217 // "pulling backward". See https://github.com/w3c/media-source/issues/187.
1218 CheckExpectedRangesByTimestamp(video_.get(), "{ [50,70) }");
1220 SeekStream(video_.get(), Milliseconds(0));
1221 CheckReadsThenReadStalls(video_.get(), "50 60 40");
1224 TEST_P(FrameProcessorTest, OOOKeyframePts_1) {
1226 AddTestTracks(HAS_AUDIO);
1227 frame_processor_->SetSequenceMode(use_sequence_mode_);
1229 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1010)));
1230 // Note that the following does not contain a DTS continuity, but *does*
1231 // contain a PTS discontinuity (keyframe at 0.1s after keyframe at 1s).
1232 EXPECT_TRUE(ProcessFrames("0K 1000|10K 100|20K", ""));
1234 // Force sequence mode to place the next frames where segments mode would put
1235 // them, to simplify this test case.
1236 if (use_sequence_mode_)
1237 SetTimestampOffset(Milliseconds(500));
1239 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(510)));
1240 EXPECT_TRUE(ProcessFrames("500|100K", ""));
1241 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1243 // Note that the PTS discontinuity (100ms) in the first ProcessFrames() call,
1244 // above, overlaps the previously buffered range [0,1010), so the frame at
1245 // 100ms is processed with an adjusted coded frame group start to be 0.001ms,
1246 // which is just after the highest timestamp before it in the overlapped
1247 // range. This enables it to be continuous with the frame before it. The
1248 // remainder of the overlapped range (the buffer at [1000,1010)) is adjusted
1249 // to have a range start time at the split point (110), and is within fudge
1250 // room and merged into [0,110). The same happens with the buffer appended
1252 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,1010) }");
1253 CheckReadsThenReadStalls(audio_.get(), "0 100 500 1000");
1256 TEST_P(FrameProcessorTest, OOOKeyframePts_2) {
1258 AddTestTracks(HAS_AUDIO);
1259 frame_processor_->SetSequenceMode(use_sequence_mode_);
1261 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1010)));
1262 EXPECT_TRUE(ProcessFrames("0K 1000|10K", ""));
1264 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1010)));
1265 EXPECT_TRUE(ProcessFrames("100|20K", ""));
1267 // Note that the PTS discontinuity (100ms) in the first ProcessFrames() call,
1268 // above, overlaps the previously buffered range [0,1010), so the frame at
1269 // 100ms is processed with an adjusted coded frame group start to be 0.001ms,
1270 // which is just after the highest timestamp before it in the overlapped
1271 // range. This enables it to be continuous with the frame before it. The
1272 // remainder of the overlapped range (the buffer at [1000,1010)) is adjusted
1273 // to have a range start time at the split point (110), and is within fudge
1274 // room and merged into [0,110).
1275 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,1010) }");
1276 CheckReadsThenReadStalls(audio_.get(), "0 100 1000");
1279 TEST_P(FrameProcessorTest, AudioNonKeyframeChangedToKeyframe) {
1280 // Verifies that an audio non-keyframe is changed to a keyframe with a media
1281 // log warning. An exact overlap append of the preceding keyframe is also done
1282 // to ensure that the (original non-keyframe) survives (because it was changed
1283 // to a keyframe, so no longer depends on the original preceding keyframe).
1284 // The sequence mode test version uses SetTimestampOffset to make it behave
1285 // like segments mode to simplify the tests.
1286 // Note, see the NonkeyframeAudioBuffering tests to verify buffering of audio
1287 // nonkeyframes for codec(s) that use nonkeyframes.
1289 AddTestTracks(HAS_AUDIO);
1290 frame_processor_->SetSequenceMode(use_sequence_mode_);
1292 EXPECT_MEDIA_LOG(AudioNonKeyframe(10000, 10000));
1293 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(30)));
1294 EXPECT_TRUE(ProcessFrames("0K 10 20K", ""));
1296 if (use_sequence_mode_)
1297 SetTimestampOffset(Milliseconds(0));
1299 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1300 EXPECT_TRUE(ProcessFrames("0K", ""));
1302 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,30) }");
1303 SeekStream(audio_.get(), Milliseconds(0));
1304 CheckReadsThenReadStalls(audio_.get(), "0 10 20");
1307 TEST_P(FrameProcessorTest, TimestampOffsetNegativeDts) {
1308 // Shift a GOP earlier using timestampOffset such that the GOP
1309 // starts with negative DTS, but PTS 0.
1311 AddTestTracks(HAS_VIDEO);
1312 frame_processor_->SetSequenceMode(use_sequence_mode_);
1314 if (!use_sequence_mode_) {
1315 // Simulate the offset that sequence mode would apply, to make the results
1316 // the same regardless of sequence vs segments mode.
1317 SetTimestampOffset(Milliseconds(-100));
1320 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
1321 EXPECT_TRUE(ProcessFrames("", "100|70K 130|80"));
1322 EXPECT_EQ(Milliseconds(-100), timestamp_offset_);
1323 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,40) }");
1324 SeekStream(video_.get(), Milliseconds(0));
1325 CheckReadsThenReadStalls(video_.get(), "0:100 30:130");
1328 TEST_P(FrameProcessorTest, LargeTimestampOffsetJumpForward) {
1329 // Verifies that jumps forward in buffers emitted from the coded frame
1330 // processing algorithm can create discontinuous buffered ranges if those
1331 // jumps are large enough, in both kinds of AppendMode.
1333 AddTestTracks(HAS_AUDIO);
1334 frame_processor_->SetSequenceMode(use_sequence_mode_);
1336 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1337 EXPECT_TRUE(ProcessFrames("0K", ""));
1339 SetTimestampOffset(Milliseconds(5000));
1341 // Along with the new timestampOffset set above, this should cause a large
1342 // jump forward in both PTS and DTS for both sequence and segments append
1344 if (use_sequence_mode_) {
1345 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(5010)));
1347 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10010)));
1349 EXPECT_TRUE(ProcessFrames("5000|100K", ""));
1350 if (use_sequence_mode_) {
1351 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1353 EXPECT_EQ(Milliseconds(5000), timestamp_offset_);
1356 if (use_sequence_mode_) {
1357 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) [5000,5010) }");
1358 CheckReadsThenReadStalls(audio_.get(), "0");
1359 SeekStream(audio_.get(), Milliseconds(5000));
1360 CheckReadsThenReadStalls(audio_.get(), "5000");
1362 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) [10000,10010) }");
1363 CheckReadsThenReadStalls(audio_.get(), "0");
1364 SeekStream(audio_.get(), Milliseconds(10000));
1365 CheckReadsThenReadStalls(audio_.get(), "10000:5000");
1369 TEST_P(FrameProcessorTest, ContinuousDts_SapType2_and_PtsJumpForward) {
1371 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1372 frame_processor_->SetSequenceMode(use_sequence_mode_);
1374 // Make the sequence mode buffering appear just like segments mode to simplify
1376 if (use_sequence_mode_)
1377 SetTimestampOffset(Milliseconds(1060));
1379 // Note that the PTS of GOP non-keyframes earlier than the keyframe doesn't
1380 // modify the GOP start of the buffered range here. This may change if we
1381 // decide to improve spec for SAP Type 2 GOPs that begin a coded frame group.
1382 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1383 Milliseconds(1060)));
1384 EXPECT_CALL(callbacks_,
1386 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1387 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("1.06", "1"));
1388 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1389 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1390 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1070)));
1391 EXPECT_TRUE(ProcessFrames(
1392 "", "1060|0K 1000|10 1050|20 1010|30 1040|40 1020|50 1030|60"));
1393 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1394 CheckExpectedRangesByTimestamp(video_.get(), "{ [1060,1070) }");
1396 // Process just the keyframe of the next SAP Type 2 GOP in decode continuity
1397 // with the previous one.
1398 // Note that this second GOP is buffered continuous with the first because
1399 // there is no decode discontinuity detected. This results in inclusion of
1400 // the significant PTS jump forward in the same continuous range.
1403 OnGroupStart(DemuxerStream::VIDEO,
1404 DecodeTimestamp::FromPresentationTime(Milliseconds(60)),
1405 Milliseconds(1070)));
1406 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1407 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1140)));
1408 EXPECT_TRUE(ProcessFrames("", "1130|70K"));
1409 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1410 CheckExpectedRangesByTimestamp(video_.get(), "{ [1060,1140) }");
1412 // Process the remainder of the second GOP.
1413 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1414 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1140)));
1416 ProcessFrames("", "1070|80 1120|90 1080|100 1110|110 1090|120 1100|130"));
1417 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1418 CheckExpectedRangesByTimestamp(video_.get(), "{ [1060,1140) }");
1420 // [1060,1140) should demux continuously without read stall in the middle.
1421 SeekStream(video_.get(), Milliseconds(1060));
1422 CheckReadsThenReadStalls(
1424 "1060 1000 1050 1010 1040 1020 1030 1130 1070 1120 1080 1110 1090 1100");
1425 // Verify that seek and read of the second GOP is correct.
1426 SeekStream(video_.get(), Milliseconds(1130));
1427 CheckReadsThenReadStalls(video_.get(), "1130 1070 1120 1080 1110 1090 1100");
1430 TEST_P(FrameProcessorTest, ContinuousDts_NewGopEndOverlapsLastGop_1) {
1431 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1432 // PTS interval overlapping the previous append.
1433 // Tests SAP-Type-1 GOPs, where newly appended GOP overlaps a nonkeyframe of
1434 // the last GOP appended.
1436 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1437 frame_processor_->SetSequenceMode(use_sequence_mode_);
1439 // Make the sequence mode buffering appear just like segments mode to simplify
1441 if (use_sequence_mode_)
1442 SetTimestampOffset(Milliseconds(100));
1444 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1445 Milliseconds(100)));
1446 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1447 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
1448 EXPECT_TRUE(ProcessFrames("", "100|0K 110|10 120|20 130|30"));
1449 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1453 OnGroupStart(DemuxerStream::VIDEO,
1454 DecodeTimestamp::FromPresentationTime(Milliseconds(30)),
1455 Milliseconds(125)));
1456 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1457 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(165)));
1458 EXPECT_TRUE(ProcessFrames("", "125|40K 135|50 145|60 155|70"));
1459 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1461 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,165) }");
1462 CheckReadsThenReadStalls(video_.get(), "100 110 120 125 135 145 155");
1465 TEST_P(FrameProcessorTest, ContinuousDts_NewGopEndOverlapsLastGop_2) {
1466 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1467 // PTS interval overlapping the previous append.
1468 // Tests SAP-Type 1 GOPs, where newly appended GOP overlaps the keyframe of
1469 // the last GOP appended.
1471 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1472 frame_processor_->SetSequenceMode(use_sequence_mode_);
1474 // Make the sequence mode buffering appear just like segments mode to simplify
1476 if (use_sequence_mode_)
1477 SetTimestampOffset(Milliseconds(100));
1479 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1480 Milliseconds(100)));
1481 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1482 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
1483 EXPECT_TRUE(ProcessFrames("", "100|0K 110|10 120|20K 130|30"));
1484 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1488 OnGroupStart(DemuxerStream::VIDEO,
1489 DecodeTimestamp::FromPresentationTime(Milliseconds(30)),
1490 Milliseconds(115)));
1491 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1492 // TODO(wolenetz): Duration shouldn't be allowed to possibly increase to 140ms
1493 // here. See https://crbug.com/763620.
1494 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
1495 EXPECT_TRUE(ProcessFrames("", "115|40K 125|50"));
1496 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1498 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,135) }");
1499 CheckReadsThenReadStalls(video_.get(), "100 110 115 125");
1502 TEST_P(FrameProcessorTest, ContinuousDts_NewSap2GopEndOverlapsLastGop_1) {
1503 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1504 // PTS interval overlapping the previous append, using SAP Type 2 GOPs.
1505 // Tests SAP-Type 2 GOPs, where newly appended GOP overlaps nonkeyframes of
1506 // the last GOP appended.
1508 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1509 frame_processor_->SetSequenceMode(use_sequence_mode_);
1511 // Make the sequence mode buffering appear just like segments mode to simplify
1513 if (use_sequence_mode_)
1514 SetTimestampOffset(Milliseconds(120));
1516 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1517 Milliseconds(120)));
1518 EXPECT_CALL(callbacks_,
1520 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1521 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.12", "0.1"));
1522 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1523 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1524 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
1525 EXPECT_TRUE(ProcessFrames("", "120|0K 100|10 130|20 110|30"));
1526 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1528 // Note, we *don't* expect another OnGroupStart during the next ProcessFrames,
1529 // since the next GOP's keyframe PTS is after the first GOP and close enough
1530 // to be assured adjacent.
1531 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1532 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1533 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(165)));
1534 EXPECT_TRUE(ProcessFrames("", "145|40K 125|50 155|60 135|70"));
1535 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1537 CheckExpectedRangesByTimestamp(video_.get(), "{ [120,165) }");
1538 // [120,165) should demux continuously without read stall in the middle.
1539 CheckReadsThenReadStalls(video_.get(), "120 100 130 110 145 125 155 135");
1540 // Verify that seek and read of the second GOP is correct.
1541 SeekStream(video_.get(), Milliseconds(145));
1542 CheckReadsThenReadStalls(video_.get(), "145 125 155 135");
1545 TEST_P(FrameProcessorTest, ContinuousDts_NewSap2GopEndOverlapsLastGop_2) {
1546 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1547 // PTS interval overlapping the previous append, using SAP Type 2 GOPs.
1548 // Tests SAP-Type 2 GOPs, where newly appended GOP overlaps the keyframe of
1549 // last GOP appended.
1551 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1552 frame_processor_->SetSequenceMode(use_sequence_mode_);
1554 // Make the sequence mode buffering appear just like segments mode to simplify
1556 if (use_sequence_mode_)
1557 SetTimestampOffset(Milliseconds(120));
1559 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1560 Milliseconds(120)));
1561 EXPECT_CALL(callbacks_,
1563 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1564 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.12", "0.1"));
1565 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1566 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1567 // There is a second GOP that is SAP-Type-2 within this first ProcessFrames,
1568 // with PTS jumping forward far enough to trigger group start signalling and a
1572 OnGroupStart(DemuxerStream::VIDEO,
1573 DecodeTimestamp::FromPresentationTime(Milliseconds(30)),
1574 Milliseconds(140)));
1575 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1576 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(180)));
1577 EXPECT_TRUE(ProcessFrames(
1578 "", "120|0K 100|10 130|20 110|30 160|40K 140|50 170|60 150|70"));
1579 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1583 OnGroupStart(DemuxerStream::VIDEO,
1584 DecodeTimestamp::FromPresentationTime(Milliseconds(70)),
1585 Milliseconds(155)));
1586 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1587 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1588 // TODO(wolenetz): Duration shouldn't be allowed to possibly increase to 180ms
1589 // here. See https://crbug.com/763620.
1590 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(180)));
1591 EXPECT_TRUE(ProcessFrames("", "155|80K 145|90"));
1592 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1594 CheckExpectedRangesByTimestamp(video_.get(), "{ [120,165) }");
1595 // [120,165) should demux continuously without read stall in the middle.
1596 CheckReadsThenReadStalls(video_.get(), "120 100 130 110 155 145");
1597 // Verify seek and read of the second GOP is correct.
1598 SeekStream(video_.get(), Milliseconds(155));
1599 CheckReadsThenReadStalls(video_.get(), "155 145");
1602 TEST_P(FrameProcessorTest,
1603 ContinuousDts_NewSap2GopEndOverlapsLastGop_3_GopByGop) {
1604 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1605 // PTS interval overlapping the previous append, using SAP Type 2 GOPs. Tests
1606 // SAP-Type 2 GOPs, where newly appended GOP overlaps enough nonkeyframes of
1607 // the previous GOP such that dropped decode dependencies might cause problems
1608 // if the first nonkeyframe with PTS prior to the GOP's keyframe PTS is
1609 // flushed at the same time as its keyframe, but the second GOP's keyframe PTS
1610 // is close enough to the end of the first GOP's presentation interval to not
1611 // signal a new coded frame group start.
1613 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1614 frame_processor_->SetSequenceMode(use_sequence_mode_);
1616 // Make the sequence mode buffering appear just like segments mode to simplify
1618 if (use_sequence_mode_)
1619 SetTimestampOffset(Milliseconds(500));
1621 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1622 Milliseconds(500)));
1623 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1624 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(530)));
1625 EXPECT_TRUE(ProcessFrames("", "500|0K 520|10 510|20"));
1626 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,530) }");
1628 EXPECT_CALL(callbacks_,
1630 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1631 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.54", "0.52"));
1632 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1633 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1634 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(550)));
1635 EXPECT_TRUE(ProcessFrames("", "540|30K 520|40 530|50"));
1637 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,550) }");
1638 SeekStream(video_.get(), Milliseconds(500));
1639 CheckReadsThenReadStalls(video_.get(), "500 520 510 540 520 530");
1642 TEST_P(FrameProcessorTest,
1643 ContinuousDts_NewSap2GopEndOverlapsLastGop_3_FrameByFrame) {
1644 // Tests that the buffered range results match the previous GopByGop test if
1645 // each frame of the second GOP is explicitly appended by the app
1648 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1649 frame_processor_->SetSequenceMode(use_sequence_mode_);
1651 // Make the sequence mode buffering appear just like segments mode to simplify
1653 if (use_sequence_mode_)
1654 SetTimestampOffset(Milliseconds(500));
1656 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1657 Milliseconds(500)));
1658 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1659 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(530)));
1660 EXPECT_TRUE(ProcessFrames("", "500|0K 520|10 510|20"));
1661 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,530) }");
1663 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1664 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(550)));
1665 EXPECT_TRUE(ProcessFrames("", "540|30K"));
1667 EXPECT_CALL(callbacks_,
1669 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1670 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.54", "0.52"));
1671 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1672 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(550)));
1673 EXPECT_TRUE(ProcessFrames("", "520|40"));
1675 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1676 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(550)));
1677 EXPECT_TRUE(ProcessFrames("", "530|50"));
1679 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,550) }");
1680 SeekStream(video_.get(), Milliseconds(500));
1681 CheckReadsThenReadStalls(video_.get(), "500 520 510 540 520 530");
1684 TEST_P(FrameProcessorTest,
1685 ContinuousDts_NewSap2GopEndOverlapsLastGop_4_GopByGop) {
1686 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1687 // PTS interval overlapping the previous append, using SAP Type 2 GOPs. Tests
1688 // SAP-Type 2 GOPs, where newly appended GOP overlaps enough nonkeyframes of
1689 // the previous GOP such that dropped decode dependencies might cause problems
1690 // if the first nonkeyframe with PTS prior to the GOP's keyframe PTS is
1691 // flushed at the same time as its keyframe.
1693 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1694 frame_processor_->SetSequenceMode(use_sequence_mode_);
1696 // Make the sequence mode buffering appear just like segments mode to simplify
1698 if (use_sequence_mode_)
1699 SetTimestampOffset(Milliseconds(500));
1701 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1702 Milliseconds(500)));
1703 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1704 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(530)));
1705 EXPECT_TRUE(ProcessFrames("", "500|0K 520|10 510|20"));
1706 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,530) }");
1710 OnGroupStart(DemuxerStream::VIDEO,
1711 DecodeTimestamp::FromPresentationTime(Milliseconds(20)),
1712 Milliseconds(530)));
1713 EXPECT_CALL(callbacks_,
1715 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1716 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.55", "0.52"));
1717 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1718 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1719 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1720 EXPECT_TRUE(ProcessFrames("", "550|30K 520|40 530|50 540|60"));
1722 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,560) }");
1723 SeekStream(video_.get(), Milliseconds(500));
1724 CheckReadsThenReadStalls(video_.get(), "500 520 510 550 520 530 540");
1727 TEST_P(FrameProcessorTest,
1728 ContinuousDts_NewSap2GopEndOverlapsLastGop_4_FrameByFrame) {
1729 // Tests that the buffered range results match the previous GopByGop test if
1730 // each frame of the second GOP is explicitly appended by the app
1733 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1734 frame_processor_->SetSequenceMode(use_sequence_mode_);
1736 // Make the sequence mode buffering appear just like segments mode to simplify
1738 if (use_sequence_mode_)
1739 SetTimestampOffset(Milliseconds(500));
1741 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1742 Milliseconds(500)));
1743 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1744 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(530)));
1745 EXPECT_TRUE(ProcessFrames("", "500|0K 520|10 510|20"));
1746 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,530) }");
1750 OnGroupStart(DemuxerStream::VIDEO,
1751 DecodeTimestamp::FromPresentationTime(Milliseconds(20)),
1752 Milliseconds(530)));
1753 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1754 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1755 EXPECT_TRUE(ProcessFrames("", "550|30K"));
1757 EXPECT_CALL(callbacks_,
1759 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1760 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.55", "0.52"));
1761 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1762 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1763 EXPECT_TRUE(ProcessFrames("", "520|40"));
1765 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1766 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1767 EXPECT_TRUE(ProcessFrames("", "530|50"));
1769 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1770 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1771 EXPECT_TRUE(ProcessFrames("", "540|60"));
1773 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,560) }");
1774 SeekStream(video_.get(), Milliseconds(500));
1775 CheckReadsThenReadStalls(video_.get(), "500 520 510 550 520 530 540");
1778 TEST_P(FrameProcessorTest, ContinuousDts_GopKeyframePtsOrder_2_1_3) {
1779 // White-box test, demonstrating expected behavior for a specially crafted
1780 // sequence that "should" be unusual, but gracefully handled:
1781 // SAP-Type 1 GOPs for simplicity of test. First appended GOP is highest in
1782 // timeline. Second appended GOP is earliest in timeline. Third appended GOP
1783 // is continuous in time with highest end time of first appended GOP. The
1784 // result should be a single continuous range containing just the second and
1785 // third appended GOPs (since the first-appended GOP was overlap-removed from
1786 // the timeline due to being in the gap between the second and third appended
1787 // GOPs). Note that MseTrackBuffer::ResetHighestPresentationTimestamp() done
1788 // at the beginning of the second appended GOP is the key to gracefully
1789 // handling the third appended GOP.
1791 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1792 frame_processor_->SetSequenceMode(use_sequence_mode_);
1794 // Make the sequence mode buffering appear just like segments mode to simplify
1796 if (use_sequence_mode_)
1797 SetTimestampOffset(Milliseconds(200));
1799 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1800 Milliseconds(200)));
1801 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1802 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(240)));
1803 EXPECT_TRUE(ProcessFrames("", "200|0K 210|10 220|20 230|30"));
1804 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1805 CheckExpectedRangesByTimestamp(video_.get(), "{ [200,240) }");
1809 OnGroupStart(DemuxerStream::VIDEO,
1810 DecodeTimestamp::FromPresentationTime(Milliseconds(30)),
1811 Milliseconds(100)));
1812 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1813 // TODO(wolenetz): Duration shouldn't be allowed to possibly increase to 240ms
1814 // here. See https://crbug.com/763620.
1815 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(240)));
1816 EXPECT_TRUE(ProcessFrames("", "100|40K 110|50 120|60 130|70"));
1817 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1818 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [200,240) }");
1822 OnGroupStart(DemuxerStream::VIDEO,
1823 DecodeTimestamp::FromPresentationTime(Milliseconds(70)),
1824 Milliseconds(140)));
1825 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1826 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(260)));
1827 EXPECT_TRUE(ProcessFrames("", "240|80K 250|90"));
1828 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1829 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,260) }");
1831 SeekStream(video_.get(), Milliseconds(100));
1832 CheckReadsThenReadStalls(video_.get(), "100 110 120 130 240 250");
1835 TEST_P(FrameProcessorTest, ContinuousPts_DiscontinuousDts_AcrossGops) {
1836 // GOPs which overlap in DTS, but are continuous in PTS should be buffered
1837 // correctly. In particular, monotonic increase of DTS in continuous-in-PTS
1838 // append sequences is not required across GOPs (just within GOPs).
1840 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1841 frame_processor_->SetSequenceMode(use_sequence_mode_);
1843 // Make the sequence mode buffering appear just like segments mode to simplify
1845 if (use_sequence_mode_)
1846 SetTimestampOffset(Milliseconds(200));
1850 OnGroupStart(DemuxerStream::VIDEO,
1851 DecodeTimestamp::FromPresentationTime(Milliseconds(200)),
1852 Milliseconds(200)));
1853 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1854 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(240)));
1855 EXPECT_TRUE(ProcessFrames("", "200K 210 220 230"));
1856 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1857 CheckExpectedRangesByTimestamp(video_.get(), "{ [200,240) }");
1861 OnGroupStart(DemuxerStream::VIDEO,
1862 DecodeTimestamp::FromPresentationTime(Milliseconds(225)),
1863 Milliseconds(240)));
1864 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1865 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(280)));
1866 // Append a second GOP whose first DTS is below the last DTS of the first GOP,
1867 // but whose PTS interval is continuous with the end of the first GOP.
1868 EXPECT_TRUE(ProcessFrames("", "240|225K 250|235 260|245 270|255"));
1869 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1870 SeekStream(video_.get(), Milliseconds(200));
1872 CheckExpectedRangesByTimestamp(video_.get(), "{ [200,280) }");
1873 CheckReadsThenReadStalls(video_.get(), "200 210 220 230 240 250 260 270");
1876 TEST_P(FrameProcessorTest, OnlyKeyframes_ContinuousDts_ContinousPts_1) {
1877 // Verifies that precisely one group start and one stream append occurs for a
1878 // single continuous set of frames.
1880 AddTestTracks(HAS_AUDIO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1881 if (use_sequence_mode_)
1882 frame_processor_->SetSequenceMode(true);
1884 // Default test frame duration is 10 milliseconds.
1886 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::AUDIO, DecodeTimestamp(),
1887 base::TimeDelta()));
1888 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1889 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
1890 EXPECT_TRUE(ProcessFrames("0K 10K 20K 30K", ""));
1891 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1893 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
1894 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
1897 TEST_P(FrameProcessorTest, OnlyKeyframes_ContinuousDts_ContinuousPts_2) {
1898 // Verifies that precisely one group start and one stream append occurs while
1899 // processing a single continuous set of frames that uses fudge room to just
1900 // barely remain adjacent.
1902 AddTestTracks(HAS_AUDIO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1903 if (use_sequence_mode_)
1904 frame_processor_->SetSequenceMode(true);
1906 frame_duration_ = Milliseconds(5);
1908 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::AUDIO, DecodeTimestamp(),
1909 base::TimeDelta()));
1910 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1911 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(35)));
1912 EXPECT_TRUE(ProcessFrames("0K 10K 20K 30K", ""));
1913 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1915 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,35) }");
1916 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
1919 TEST_P(FrameProcessorTest,
1920 OnlyKeyframes_ContinuousDts_DiscontinuousPtsJustBeyondFudgeRoom) {
1921 // Verifies that multiple group starts and distinct appends occur
1922 // when processing a single DTS-continuous set of frames with PTS deltas that
1923 // just barely exceed the adjacency assumption in FrameProcessor.
1925 AddTestTracks(HAS_AUDIO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1926 if (use_sequence_mode_)
1927 frame_processor_->SetSequenceMode(true);
1929 frame_duration_ = base::Microseconds(4999);
1931 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::AUDIO, DecodeTimestamp(),
1932 base::TimeDelta()));
1933 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1934 // Frame "10|5K" following "0K" triggers start of new group and eventual
1936 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::AUDIO, DecodeTimestamp(),
1938 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1940 // Frame "20|10K" following "10|5K" triggers start of new group and eventual
1944 OnGroupStart(DemuxerStream::AUDIO,
1945 DecodeTimestamp::FromPresentationTime(Milliseconds(5)),
1946 Milliseconds(10) + frame_duration_));
1947 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1949 // Frame "30|15K" following "20|10K" triggers start of new group and
1953 OnGroupStart(DemuxerStream::AUDIO,
1954 DecodeTimestamp::FromPresentationTime(Milliseconds(10)),
1955 Milliseconds(20) + frame_duration_));
1956 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1958 EXPECT_CALL(callbacks_, PossibleDurationIncrease(base::Microseconds(34999)));
1959 EXPECT_TRUE(ProcessFrames("0K 10|5K 20|10K 30|15K", ""));
1960 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1962 // Note that the result is still buffered continuous since DTS was continuous
1963 // and PTS was monotonically increasing (such that each group start was
1964 // signalled by FrameProcessor to be continuous with the end of the previous
1966 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,34) }");
1967 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
1970 TEST_P(FrameProcessorTest,
1971 GroupEndTimestampDecreaseWithinMediaSegmentShouldWarn) {
1972 // This parse warning requires:
1973 // 1) a decode time discontinuity within the set of frames being processed,
1974 // 2) the highest frame end time of any frame successfully processed
1975 // before that discontinuity is higher than the highest frame end time of
1976 // all frames processed after that discontinuity.
1977 // TODO(wolenetz): Adjust this case once direction on spec is informed by
1978 // data. See https://crbug.com/920853 and
1979 // https://github.com/w3c/media-source/issues/203.
1980 if (use_sequence_mode_) {
1981 // Sequence mode modifies the presentation timestamps following a decode
1982 // discontinuity such that this scenario should not repro with that mode.
1983 DVLOG(1) << "Skipping segments mode variant; inapplicable to this case.";
1988 AddTestTracks(HAS_VIDEO);
1990 EXPECT_CALL(callbacks_,
1991 OnParseWarning(SourceBufferParseWarning::
1992 kGroupEndTimestampDecreaseWithinMediaSegment));
1994 frame_duration_ = Milliseconds(10);
1995 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(15)));
1996 EXPECT_TRUE(ProcessFrames("", "0K 10K 5|40K"));
1997 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1999 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,15) }");
2000 CheckReadsThenReadStalls(video_.get(), "0 5");
2003 TEST_P(FrameProcessorTest, NonkeyframeAudioBuffering_BasicOperation) {
2004 // With the support for audio nonkeyframe buffering enabled, buffer a couple
2005 // continuous groups of audio key and nonkey frames.
2006 // Note, see the AudioNonKeyframeChangedToKeyframe test that tests where
2007 // nonkeyframe audio buffering is not supported, and instead takes a
2008 // workaround that forces all audio to be keyframe.
2010 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2011 if (use_sequence_mode_)
2012 frame_processor_->SetSequenceMode(true);
2014 // Default test frame duration is 10 milliseconds.
2015 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(80)));
2016 EXPECT_TRUE(ProcessFrames("0K 10 20 30 40K 50 60 70", ""));
2017 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2019 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,80) }");
2020 CheckReadsAndKeyframenessThenReadStalls(audio_.get(),
2021 "0K 10N 20N 30N 40K 50N 60N 70N");
2024 TEST_P(FrameProcessorTest, NonkeyframeAudioBuffering_BasicOverlaps) {
2025 // With the support for audio nonkeyframe buffering enabled, buffer a few
2026 // groups of audio key and nonkey frames which overlap each other.
2027 // For sequence mode versions, timestampOffset is adjusted to make it act like
2030 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2031 if (use_sequence_mode_) {
2032 frame_processor_->SetSequenceMode(true);
2033 SetTimestampOffset(Milliseconds(10));
2036 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
2037 EXPECT_TRUE(ProcessFrames("10K 20 30 40 50", ""));
2038 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2039 CheckExpectedRangesByTimestamp(audio_.get(), "{ [10,60) }");
2041 // End-overlap the last nonkeyframe appended with a keyframe.
2043 if (use_sequence_mode_)
2044 SetTimestampOffset(Milliseconds(50));
2046 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(70)));
2047 EXPECT_TRUE(ProcessFrames("50K 60", ""));
2048 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2049 CheckExpectedRangesByTimestamp(audio_.get(), "{ [10,70) }");
2051 // Front-overlap the original group of frames.
2053 if (use_sequence_mode_)
2054 SetTimestampOffset(Milliseconds(0));
2056 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
2057 EXPECT_TRUE(ProcessFrames("0K 10", ""));
2058 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2059 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,70) }");
2061 SeekStream(audio_.get(), Milliseconds(0));
2062 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "0K 10N 50K 60N");
2065 TEST_P(FrameProcessorTest,
2066 NonkeyframeAudioBuffering_InitialNonkeyframesNotBuffered) {
2067 // With the support for audio nonkeyframe buffering enabled, try to buffer
2068 // some frames beginning with a nonkeyframe and observe initial nonkeyframe(s)
2069 // are not buffered.
2071 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2072 if (use_sequence_mode_)
2073 frame_processor_->SetSequenceMode(true);
2075 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
2076 EXPECT_TRUE(ProcessFrames("0 10 20K 30 40 50", ""));
2077 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2078 CheckExpectedRangesByTimestamp(audio_.get(), "{ [20,60) }");
2079 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "20K 30N 40N 50N");
2082 TEST_P(FrameProcessorTest,
2083 NonkeyframeAudioBuffering_InvalidDecreasingNonkeyframePts) {
2084 // With the support for audio nonkeyframe buffering enabled, try to buffer an
2085 // invalid sequence of nonkeyframes: decreasing presentation timestamps are
2086 // not supported for audio nonkeyframes. For sequence mode versions,
2087 // timestampOffset is adjusted to make it act like segments mode.
2089 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2090 if (use_sequence_mode_) {
2091 frame_processor_->SetSequenceMode(true);
2092 SetTimestampOffset(Milliseconds(100));
2095 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(110)));
2096 EXPECT_TRUE(ProcessFrames("100K", ""));
2097 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2098 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,110) }");
2100 // Processing an audio nonkeyframe with lower PTS than the previous frame
2102 EXPECT_MEDIA_LOG(AudioNonKeyframeOutOfOrder());
2103 EXPECT_FALSE(ProcessFrames("90|110", ""));
2106 TEST_P(FrameProcessorTest,
2107 NonkeyframeAudioBuffering_ValidDecreasingKeyframePts) {
2108 // With the support for audio nonkeyframe buffering enabled, try to buffer a
2109 // valid sequence of key and nonkeyframes: decreasing presentation timestamps
2110 // are supported for keyframes. For sequence mode versions, timestampOffset is
2111 // adjusted to make it act like segments mode.
2113 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2114 if (use_sequence_mode_) {
2115 frame_processor_->SetSequenceMode(true);
2116 SetTimestampOffset(Milliseconds(100));
2119 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(130)));
2120 EXPECT_TRUE(ProcessFrames("100K 110 120", ""));
2121 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2122 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
2124 // Processing an audio keyframe with lower PTS than the previous frame
2125 // should succeed, since it is a keyframe. Here, we use continuous DTS to
2126 // ensure we precisely target the nonkeyframe monotonicity check when a
2127 // keyframe is not required by the track buffer currently (and to make
2128 // sequence mode versions act like segments mode without further manual
2129 // adjustment of timestamp offset.) The original nonkeyframe at PTS 110 should
2130 // be overlap-removed, and the one at PTS 120 should have be removed as a
2131 // result of depending on that removed PTS 110 nonkeyframe.
2132 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(130)));
2133 EXPECT_TRUE(ProcessFrames("110|130K", ""));
2134 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2135 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,120) }");
2136 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "100K 110K");
2139 TEST_P(FrameProcessorTest,
2140 NonkeyframeAudioBuffering_ValidSameNonKeyframePts_1) {
2141 // With the support for audio nonkeyframe buffering enabled, try to buffer a
2142 // valid sequence of a keyframe and a nonkeyframe: non-increasing presentation
2143 // timestamps are supported for audio nonkeyframes, so long as they don't
2144 // decrease. For sequence mode versions, timestampOffset is adjusted to make
2145 // it act like segments mode.
2147 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2148 if (use_sequence_mode_) {
2149 frame_processor_->SetSequenceMode(true);
2150 SetTimestampOffset(Milliseconds(100));
2153 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(110)));
2154 EXPECT_TRUE(ProcessFrames("100K", ""));
2155 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2156 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,110) }");
2158 // Processing an audio nonkeyframe with same PTS as the previous frame should
2159 // succeed, though there is presentation interval overlap causing removal of
2160 // the previous frame (in this case, a keyframe), and hence the new dependent
2161 // nonkeyframe is not buffered.
2162 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(110)));
2163 EXPECT_TRUE(ProcessFrames("100|110", ""));
2164 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2165 CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
2166 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "");
2169 TEST_P(FrameProcessorTest,
2170 NonkeyframeAudioBuffering_ValidSameNonKeyframePts_2) {
2171 // With the support for audio nonkeyframe buffering enabled, try to buffer a
2172 // valid sequence of nonkeyframes: non-increasing presentation timestamps are
2173 // supported for audio nonkeyframes, so long as they don't decrease. For
2174 // sequence mode versions, timestampOffset is adjusted to make it act like
2177 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2178 if (use_sequence_mode_) {
2179 frame_processor_->SetSequenceMode(true);
2180 SetTimestampOffset(Milliseconds(100));
2183 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(120)));
2184 EXPECT_TRUE(ProcessFrames("100K 110", ""));
2185 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2186 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,120) }");
2188 // Processing an audio nonkeyframe with same PTS as the previous frame should
2189 // succeed, though there is presentation interval overlap causing removal of
2190 // the previous nonkeyframe, and hence the new dependent nonkeyframe is not
2192 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(120)));
2193 EXPECT_TRUE(ProcessFrames("110|120", ""));
2194 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2195 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,110) }");
2196 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "100K");
2199 TEST_P(FrameProcessorTest,
2200 NonkeyframeAudioBuffering_AppendWindowFilterDroppedPrerollKeyframe) {
2201 // For simplicity currently, if the preroll (keyframe) buffer was entirely
2202 // prior to the append window and dropped, an approximately continuous
2203 // keyframe is still required to use that dropped frame as preroll (for
2204 // simplicity). This may change in future if append window trimming of
2205 // nonkeyframes with a fully excluded preroll keyframe is commonly needed to
2208 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2209 if (use_sequence_mode_)
2210 frame_processor_->SetSequenceMode(true);
2211 SetTimestampOffset(Milliseconds(-10));
2213 EXPECT_MEDIA_LOG(DroppedFrame("audio", -10000));
2214 if (use_sequence_mode_)
2215 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(-10)));
2217 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(0)));
2218 EXPECT_TRUE(ProcessFrames("0K", ""));
2220 // This nonkeyframe is dropped for simplicity since it depends on a preroll
2221 // keyframe which was entirely outside the append window.
2222 if (use_sequence_mode_)
2223 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(-10)));
2225 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(0)));
2226 EXPECT_TRUE(ProcessFrames("10", ""));
2228 // Only the following keyframe should buffer successfully, with no preroll.
2229 EXPECT_MEDIA_LOG(DroppedAppendWindowUnusedPreroll(-10000, -10000, 10000));
2230 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
2231 EXPECT_TRUE(ProcessFrames("20K", ""));
2233 CheckExpectedRangesByTimestamp(audio_.get(), "{ [10,20) }");
2234 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "10:20K");
2237 TEST_P(FrameProcessorTest,
2238 NonkeyframeAudioBuffering_AppendWindowFilter_TrimFront) {
2240 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2241 if (use_sequence_mode_)
2242 frame_processor_->SetSequenceMode(true);
2243 SetTimestampOffset(Milliseconds(-4));
2244 EXPECT_MEDIA_LOG(TruncatedFrame(-4000, 6000, "start", 0));
2245 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(26)));
2246 EXPECT_TRUE(ProcessFrames("0K 10 20", ""));
2247 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,26) }");
2248 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "0K 6:10N 16:20N");
2251 TEST_P(FrameProcessorTest,
2252 NonkeyframeAudioBuffering_AppendWindowFilter_TrimEnd) {
2254 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2255 if (use_sequence_mode_)
2256 frame_processor_->SetSequenceMode(true);
2258 append_window_end_ = Milliseconds(26);
2260 EXPECT_MEDIA_LOG(TruncatedFrame(20000, 30000, "end", 26000));
2261 EXPECT_MEDIA_LOG(DroppedFrameCheckAppendWindow("audio", 0, 26000));
2262 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(26)));
2263 EXPECT_TRUE(ProcessFrames("0K 10 20 30", ""));
2264 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,26) }");
2265 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "0K 10N 20N");
2268 TEST_P(FrameProcessorTest, NonkeyframeAudioBuffering_TrimSpliceOverlap) {
2269 // White-box test which focuses on the behavior of underlying
2270 // SourceBufferStream::TrimSpliceOverlap() for frame sequences involving
2271 // nonkeyframes appended by the FrameProcessor. That method detects and
2272 // performs splice trimming on every audio frame following either a
2273 // discontinuity or the beginning of ProcessFrames(), and also on audio frames
2274 // with PTS not directly continuous with the highest frame end PTS already
2275 // processed. We vary |frame_duration_| in this test to avoid confusing
2276 // int:decimal pairs in the eventual CheckReads* call.
2278 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2279 if (use_sequence_mode_)
2280 frame_processor_->SetSequenceMode(true);
2282 frame_duration_ = base::Microseconds(9750);
2283 EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
2284 EXPECT_TRUE(ProcessFrames("0K", ""));
2286 // As with all-keyframe streams, a slight jump forward should not trigger any
2287 // splicing logic, though accumulations of these may result in loss of A/V
2289 frame_duration_ = base::Microseconds(10250);
2290 EXPECT_CALL(callbacks_,
2291 PossibleDurationIncrease(Milliseconds(10) + frame_duration_));
2292 EXPECT_TRUE(ProcessFrames("10", ""));
2294 // As with all-keyframe streams, a slightly end-overlapping nonkeyframe should
2295 // not trigger any splicing logic, though accumulations of these may result in
2296 // loss of A/V sync. The difference here is there isn't even any emission of a
2297 // "too little splice overlap" media log, since the new frame is a
2299 frame_duration_ = Milliseconds(10);
2300 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(30)));
2301 EXPECT_TRUE(ProcessFrames("20", ""));
2303 // A heavily overlapping nonkeyframe should not trigger any splicing logic,
2304 // so long as it isn't completely discontinuous. This is unlike all-keyframe
2305 // audio streams, where such a heavy overlap would end-trim the overlapped
2306 // frame. Accumulations of these could rapidly lead to loss of A/V sync.
2307 // Nonkeyframe timestamp & duration metadata sequences need to be correctly
2308 // muxed to avoid this.
2309 frame_duration_ = base::Microseconds(10250);
2310 EXPECT_CALL(callbacks_,
2311 PossibleDurationIncrease(Milliseconds(22) + frame_duration_));
2312 EXPECT_TRUE(ProcessFrames("22", ""));
2314 // A keyframe that end-overlaps a nonkeyframe will trigger splicing logic.
2315 // Here, we test a "too little splice overlap" case.
2316 frame_duration_ = Milliseconds(10);
2317 EXPECT_MEDIA_LOG(SkippingSpliceTooLittleOverlap(32000, 250));
2318 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(42)));
2319 EXPECT_TRUE(ProcessFrames("32K", ""));
2321 // And a keyframe that significantly end-overlaps a nonkeyframe will trigger
2322 // splicing logic that can perform end-trimming of the overlapped frame.
2323 // First, we buffer another nonkeyframe.
2324 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(52)));
2325 EXPECT_TRUE(ProcessFrames("42", ""));
2326 // Verify correct splice behavior on significant overlap of the nonkeyframe by
2328 EXPECT_MEDIA_LOG(TrimmedSpliceOverlap(45000, 42000, 7000));
2329 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(55)));
2330 EXPECT_TRUE(ProcessFrames("45K", ""));
2332 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,55) }");
2333 CheckReadsAndKeyframenessThenReadStalls(audio_.get(),
2334 "0K 10N 20N 22N 32K 42N 45K");
2337 TEST_P(FrameProcessorTest, FrameDuration_kNoTimestamp_Fails) {
2339 AddTestTracks(HAS_AUDIO);
2340 frame_processor_->SetSequenceMode(use_sequence_mode_);
2342 frame_duration_ = kNoTimestamp;
2343 EXPECT_MEDIA_LOG(FrameDurationUnknown("audio", 1000));
2344 EXPECT_FALSE(ProcessFrames("1K", ""));
2347 TEST_P(FrameProcessorTest,
2348 Pts_BeforeTimestampOffsetApplied_kNoTimestamp_Fails) {
2350 AddTestTracks(HAS_AUDIO);
2351 frame_processor_->SetSequenceMode(use_sequence_mode_);
2353 EXPECT_MEDIA_LOG(PtsUnknown("audio"));
2354 EXPECT_FALSE(ProcessFrames("MinK", ""));
2357 TEST_P(FrameProcessorTest,
2358 Pts_BeforeTimestampOffsetApplied_kInfiniteDuration_Fails) {
2360 AddTestTracks(HAS_AUDIO);
2361 frame_processor_->SetSequenceMode(use_sequence_mode_);
2363 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("Before adjusting by timestampOffset",
2365 EXPECT_FALSE(ProcessFrames("MaxK", ""));
2368 TEST_P(FrameProcessorTest,
2369 Dts_BeforeTimestampOffsetApplied_kNoDecodeTimestamp_UsesPtsIfValid) {
2371 AddTestTracks(HAS_AUDIO);
2372 frame_processor_->SetSequenceMode(use_sequence_mode_);
2374 // When PTS is valid, but DTS is kNoDecodeTimestamp, then
2375 // StreamParserBuffer::GetDecodeTimestamp() just returns the frame's PTS.
2376 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
2377 EXPECT_TRUE(ProcessFrames("0|MinK", ""));
2379 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) }");
2380 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "0K");
2383 TEST_P(FrameProcessorTest,
2384 Dts_BeforeTimestampOffsetApplied_kMaxDecodeTimestamp_Fails) {
2386 AddTestTracks(HAS_AUDIO);
2387 frame_processor_->SetSequenceMode(use_sequence_mode_);
2389 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("Before adjusting by timestampOffset",
2391 EXPECT_FALSE(ProcessFrames("0|MaxK", ""));
2394 TEST_P(FrameProcessorTest, After_Sequence_OffsetUpdate_kNoTimestamp_Fails) {
2395 if (!use_sequence_mode_) {
2396 DVLOG(1) << "Skipping segments mode variant; inapplicable to this case.";
2401 AddTestTracks(HAS_AUDIO);
2402 frame_processor_->SetSequenceMode(use_sequence_mode_);
2404 // (-Infinity + 5)ms minus 10ms saturates to (-Infinity)ms.
2405 SetTimestampOffset(kNoTimestamp + Milliseconds(5));
2406 EXPECT_MEDIA_LOG(SequenceOffsetUpdateOutOfRange());
2407 EXPECT_FALSE(ProcessFrames("10K", ""));
2410 TEST_P(FrameProcessorTest,
2411 After_Sequence_OffsetUpdate_kInfiniteDuration_Fails) {
2412 if (!use_sequence_mode_) {
2413 DVLOG(1) << "Skipping segments mode variant; inapplicable to this case.";
2418 AddTestTracks(HAS_AUDIO);
2419 frame_processor_->SetSequenceMode(use_sequence_mode_);
2421 // (+Infinity - 5)ms minus -10ms saturates to (+Infinity)ms.
2422 SetTimestampOffset(kInfiniteDuration - Milliseconds(5));
2423 EXPECT_MEDIA_LOG(SequenceOffsetUpdateOutOfRange());
2424 EXPECT_FALSE(ProcessFrames("-10K", ""));
2427 TEST_P(FrameProcessorTest,
2428 Before_Sequence_OffsetUpdate_kInfiniteDuration_Fails) {
2429 if (!use_sequence_mode_) {
2430 DVLOG(1) << "Skipping segments mode variant; inapplicable to this case.";
2435 AddTestTracks(HAS_AUDIO);
2436 frame_processor_->SetSequenceMode(use_sequence_mode_);
2438 // Effectively sets group start timestamp to +Infinity.
2439 SetTimestampOffset(kInfiniteDuration);
2441 SequenceOffsetUpdatePreventedByOutOfRangeGroupStartTimestamp());
2443 // That infinite value fails precondition of finite value for group start
2444 // timestamp when about to update timestampOffset based upon it.
2445 EXPECT_FALSE(ProcessFrames("0K", ""));
2448 TEST_P(FrameProcessorTest, Segments_InfiniteTimestampOffset_Fails) {
2449 if (use_sequence_mode_) {
2450 DVLOG(1) << "Skipping sequence mode variant; inapplicable to this case.";
2455 AddTestTracks(HAS_AUDIO);
2456 frame_processor_->SetSequenceMode(use_sequence_mode_);
2458 SetTimestampOffset(kInfiniteDuration);
2459 EXPECT_MEDIA_LOG(OffsetOutOfRange());
2460 EXPECT_FALSE(ProcessFrames("0K", ""));
2463 TEST_P(FrameProcessorTest, Pts_AfterTimestampOffsetApplied_kNoTimestamp_Fails) {
2465 AddTestTracks(HAS_VIDEO);
2466 frame_processor_->SetSequenceMode(use_sequence_mode_);
2468 // Note, SetTimestampOffset(kNoTimestamp) hits DCHECK. This test instead
2469 // checks that the result of offset application to PTS gives parse error if
2470 // the result is <= kNoTimestamp. Getting such a result requires different
2471 // test logic for segments vs sequence append modes.
2472 if (use_sequence_mode_) {
2473 // Use an extremely out-of-order DTS/PTS GOP to get the resulting
2474 // timestampOffset needed for application to a nonkeyframe PTS (continuous
2475 // in DTS time with its GOP's keyframe), resulting with kNoTimestamp PTS.
2476 // First, calculate (-kNoTimestamp - 10ms), truncated down to nearest
2477 // millisecond, for use as keyframe PTS and DTS.
2478 frame_duration_ = Milliseconds(1);
2479 base::TimeDelta ts =
2480 Milliseconds(((kNoTimestamp + Milliseconds(10)) * -1).InMilliseconds());
2481 std::string ts_str = base::NumberToString(ts.InMilliseconds());
2483 // Append the keyframe and expect success for this step.
2484 EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
2485 EXPECT_TRUE(ProcessFrames("", ts_str + "|" + ts_str + "K"));
2486 EXPECT_EQ(timestamp_offset_.InMicroseconds(), (-1 * ts).InMicroseconds());
2488 // A nonkeyframe with the same DTS as previous frame does not cause any
2489 // discontinuity. Append such a frame, with PTS before offset applied that
2490 // saturates to kNoTimestamp when the offset is applied.
2491 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("After adjusting by timestampOffset",
2493 EXPECT_FALSE(ProcessFrames("", "-20|" + ts_str));
2495 // Set the offset to be just above kNoTimestamp, and append a frame with a
2496 // PTS that is negative by at least that small amount. The result should
2497 // saturate to kNoTimestamp for PTS.
2498 SetTimestampOffset(kNoTimestamp + Milliseconds(1));
2499 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("After adjusting by timestampOffset",
2501 EXPECT_FALSE(ProcessFrames("", "-2K"));
2505 TEST_P(FrameProcessorTest,
2506 Pts_AfterTimestampOffsetApplied_kInfiniteDuration_Fails) {
2509 AddTestTracks(HAS_VIDEO);
2510 frame_processor_->SetSequenceMode(use_sequence_mode_);
2512 // Use a video GOP with a nonkeyframe PTS that jumps forward far enough to
2513 // saturate to kInfiniteDuration after timestampOffset is applied. Take care
2514 // to avoid saturating the (earlier) keyframe's frame_end_timestamp to
2515 // kInfiniteDuration, avoiding a different parse error case.
2516 // First, calculate (kInfiniteDuration - 2ms), truncated down to nearest
2517 // millisecond for use as keyframe PTS (after timestamp offset application).
2518 // It's also used for start of DTS sequence.
2519 frame_duration_ = Milliseconds(1);
2520 base::TimeDelta ts =
2521 Milliseconds((kInfiniteDuration - Milliseconds(2)).InMilliseconds());
2523 // Append the keyframe and expect success for this step.
2524 SetTimestampOffset(ts);
2525 EXPECT_CALL(callbacks_, PossibleDurationIncrease(ts + frame_duration_));
2526 EXPECT_TRUE(ProcessFrames("", "0K"));
2528 // Sequence mode might adjust the offset. This test's logic should ensure the
2529 // offset is the same as in segments mode at this point.
2530 EXPECT_EQ(timestamp_offset_.InMicroseconds(), ts.InMicroseconds());
2532 // A nonkeyframe with same DTS as previous frame does not cause any
2533 // discontinuity. Append such a frame, with PTS jumped 3ms forwards such that
2534 // it saturates to kInfiniteDuration when offset is applied.
2535 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("After adjusting by timestampOffset",
2537 EXPECT_FALSE(ProcessFrames("", "3|0"));
2540 TEST_P(FrameProcessorTest,
2541 Dts_AfterTimestampOffsetApplied_kNoDecodeTimestamp_Fails) {
2544 AddTestTracks(HAS_AUDIO);
2545 frame_processor_->SetSequenceMode(use_sequence_mode_);
2547 SetTimestampOffset(kNoTimestamp + Milliseconds(5));
2548 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("After adjusting by timestampOffset",
2550 EXPECT_FALSE(ProcessFrames("0|-10K", ""));
2553 TEST_P(FrameProcessorTest,
2554 Dts_AfterTimestampOffsetApplied_kMaxDecodeTimestamp_Fails) {
2557 AddTestTracks(HAS_AUDIO);
2558 frame_processor_->SetSequenceMode(use_sequence_mode_);
2560 SetTimestampOffset(kInfiniteDuration - Milliseconds(5));
2561 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("After adjusting by timestampOffset",
2563 EXPECT_FALSE(ProcessFrames("0|10K", ""));
2566 TEST_P(FrameProcessorTest, FrameEndTimestamp_kInfiniteDuration_Fails) {
2569 AddTestTracks(HAS_AUDIO);
2570 frame_processor_->SetSequenceMode(use_sequence_mode_);
2572 frame_duration_ = Milliseconds(10);
2573 SetTimestampOffset(kInfiniteDuration - Milliseconds(5));
2574 EXPECT_MEDIA_LOG(FrameEndTimestampOutOfRange("audio"));
2575 EXPECT_FALSE(ProcessFrames("0|0K", ""));
2578 INSTANTIATE_TEST_SUITE_P(SequenceMode, FrameProcessorTest, Values(true));
2579 INSTANTIATE_TEST_SUITE_P(SegmentsMode, FrameProcessorTest, Values(false));
2581 } // namespace media