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/functional/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 Ranges<base::TimeDelta> r = stream->GetBufferedRanges(kInfiniteDuration);
256 std::stringstream ss;
258 for (size_t i = 0; i < r.size(); ++i) {
259 int64_t start = r.start(i).InMilliseconds();
260 int64_t end = r.end(i).InMilliseconds();
261 ss << "[" << start << "," << end << ") ";
264 EXPECT_EQ(expected, ss.str());
267 void CheckReadStalls(ChunkDemuxerStream* stream) {
271 read_callback_called_ = false;
272 stream->Read(1, base::BindOnce(&FrameProcessorTest::StoreStatusAndBuffer,
273 base::Unretained(this)));
274 base::RunLoop().RunUntilIdle();
275 } while (++loop_count < 2 && read_callback_called_ &&
276 last_read_status_ == DemuxerStream::kAborted);
278 ASSERT_FALSE(read_callback_called_ &&
279 last_read_status_ == DemuxerStream::kAborted)
280 << "2 kAborted reads in a row. Giving up.";
281 EXPECT_FALSE(read_callback_called_);
284 // Doesn't check keyframeness, but otherwise is the same as
285 // CheckReadsAndOptionallyKeyframenessThenReadStalls().
286 void CheckReadsThenReadStalls(ChunkDemuxerStream* stream,
287 const std::string& expected) {
288 CheckReadsAndOptionallyKeyframenessThenReadStalls(stream, expected, false);
291 // Checks keyframeness using
292 // CheckReadsAndOptionallyKeyframenessThenReadStalls().
293 void CheckReadsAndKeyframenessThenReadStalls(ChunkDemuxerStream* stream,
294 const std::string& expected) {
295 CheckReadsAndOptionallyKeyframenessThenReadStalls(stream, expected, true);
298 // Format of |expected| is a space-delimited sequence of
299 // timestamp_in_ms:original_timestamp_in_ms. original_timestamp_in_ms (and the
300 // colon) must be omitted if it is the same as timestamp_in_ms. If
301 // |check_keyframeness| is true, then each frame in |expected| must end with
302 // 'K' or 'N', which respectively must match the read result frames'
304 void CheckReadsAndOptionallyKeyframenessThenReadStalls(
305 ChunkDemuxerStream* stream,
306 const std::string& expected,
307 bool check_keyframeness) {
308 std::vector<std::string> timestamps = base::SplitString(
309 expected, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
310 std::stringstream ss;
311 for (size_t i = 0; i < timestamps.size(); ++i) {
315 read_callback_called_ = false;
317 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 DemuxerStream::DecoderBufferVector buffers) {
402 DCHECK_LE(buffers.size(), 1u)
403 << "FrameProcessorTest only reads a single-buffer.";
404 scoped_refptr<DecoderBuffer> buffer =
405 (buffers.empty() ? nullptr : std::move(buffers[0]));
407 if (status == DemuxerStream::kOk && buffer.get()) {
408 DVLOG(3) << __func__ << "status: " << status
409 << " ts: " << buffer->timestamp().InSecondsF();
411 DVLOG(3) << __func__ << "status: " << status << " ts: n/a";
414 read_callback_called_ = true;
415 last_read_status_ = status;
416 last_read_buffer_ = buffer;
419 void CreateAndConfigureStream(DemuxerStream::Type type,
420 bool setup_observers,
421 bool support_audio_nonkeyframes) {
422 // TODO(wolenetz/dalecurtis): Also test with splicing disabled?
424 ChunkDemuxerStream* stream;
426 case DemuxerStream::AUDIO: {
427 ASSERT_FALSE(audio_);
428 audio_ = std::make_unique<ChunkDemuxerStream>(DemuxerStream::AUDIO,
429 MediaTrack::Id("1"));
430 AudioDecoderConfig decoder_config;
431 if (support_audio_nonkeyframes) {
432 decoder_config = AudioDecoderConfig(
433 AudioCodec::kAAC, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO,
434 1000, EmptyExtraData(), EncryptionScheme::kUnencrypted);
435 decoder_config.set_profile(AudioCodecProfile::kXHE_AAC);
438 AudioDecoderConfig(AudioCodec::kVorbis, kSampleFormatPlanarF32,
439 CHANNEL_LAYOUT_STEREO, 1000, EmptyExtraData(),
440 EncryptionScheme::kUnencrypted);
442 frame_processor_->OnPossibleAudioConfigUpdate(decoder_config);
444 audio_->UpdateAudioConfig(decoder_config, false, &media_log_));
446 stream = audio_.get();
449 case DemuxerStream::VIDEO: {
450 ASSERT_FALSE(video_);
451 ASSERT_FALSE(support_audio_nonkeyframes);
452 video_ = std::make_unique<ChunkDemuxerStream>(DemuxerStream::VIDEO,
453 MediaTrack::Id("2"));
454 ASSERT_TRUE(video_->UpdateVideoConfig(TestVideoConfig::Normal(), false,
456 stream = video_.get();
459 case DemuxerStream::UNKNOWN: {
464 if (setup_observers) {
465 stream->set_append_observer_for_testing(
466 base::BindRepeating(&FrameProcessorTestCallbackHelper::OnAppend,
467 base::Unretained(&callbacks_), type));
468 stream->set_group_start_observer_for_testing(
469 base::BindRepeating(&FrameProcessorTestCallbackHelper::OnGroupStart,
470 base::Unretained(&callbacks_), type));
475 TEST_P(FrameProcessorTest, WrongTypeInAppendedBuffer) {
476 AddTestTracks(HAS_AUDIO);
477 EXPECT_FALSE(in_coded_frame_group());
479 StreamParser::BufferQueueMap buffer_queue_map;
480 const auto& audio_buffers =
481 StringToBufferQueue("0K", audio_id_, DemuxerStream::VIDEO);
482 buffer_queue_map.insert(std::make_pair(audio_id_, audio_buffers));
483 EXPECT_MEDIA_LOG(FrameTypeMismatchesTrackType("video", "1"));
485 frame_processor_->ProcessFrames(buffer_queue_map, append_window_start_,
486 append_window_end_, ×tamp_offset_));
487 EXPECT_FALSE(in_coded_frame_group());
488 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
489 CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
490 CheckReadStalls(audio_.get());
493 TEST_P(FrameProcessorTest, NonMonotonicallyIncreasingTimestampInOneCall) {
494 AddTestTracks(HAS_AUDIO);
496 EXPECT_MEDIA_LOG(ParsedBuffersNotInDTSSequence());
497 EXPECT_FALSE(ProcessFrames("10K 0K", ""));
498 EXPECT_FALSE(in_coded_frame_group());
499 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
500 CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
501 CheckReadStalls(audio_.get());
504 TEST_P(FrameProcessorTest, AudioOnly_SingleFrame) {
505 // Tests A: P(A) -> (a)
507 AddTestTracks(HAS_AUDIO);
508 if (use_sequence_mode_)
509 frame_processor_->SetSequenceMode(true);
511 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
512 EXPECT_TRUE(ProcessFrames("0K", ""));
513 EXPECT_TRUE(in_coded_frame_group());
514 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
515 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) }");
516 CheckReadsThenReadStalls(audio_.get(), "0");
519 TEST_P(FrameProcessorTest, VideoOnly_SingleFrame) {
520 // Tests V: P(V) -> (v)
522 AddTestTracks(HAS_VIDEO);
523 if (use_sequence_mode_)
524 frame_processor_->SetSequenceMode(true);
526 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
527 EXPECT_TRUE(ProcessFrames("", "0K"));
528 EXPECT_TRUE(in_coded_frame_group());
529 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
530 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,10) }");
531 CheckReadsThenReadStalls(video_.get(), "0");
534 TEST_P(FrameProcessorTest, AudioOnly_TwoFrames) {
535 // Tests A: P(A0, A10) -> (a0, a10)
537 AddTestTracks(HAS_AUDIO);
538 if (use_sequence_mode_)
539 frame_processor_->SetSequenceMode(true);
541 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
542 EXPECT_TRUE(ProcessFrames("0K 10K", ""));
543 EXPECT_TRUE(in_coded_frame_group());
544 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
545 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
546 CheckReadsThenReadStalls(audio_.get(), "0 10");
549 TEST_P(FrameProcessorTest, AudioOnly_SetOffsetThenSingleFrame) {
550 // Tests A: STSO(50)+P(A0) -> TSO==50,(a0@50)
552 AddTestTracks(HAS_AUDIO);
553 if (use_sequence_mode_)
554 frame_processor_->SetSequenceMode(true);
556 SetTimestampOffset(Milliseconds(50));
557 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
558 EXPECT_TRUE(ProcessFrames("0K", ""));
559 EXPECT_TRUE(in_coded_frame_group());
560 EXPECT_EQ(Milliseconds(50), timestamp_offset_);
561 CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) }");
563 // We do not stall on reading without seeking to 50ms due to
564 // SourceBufferStream::kSeekToStartFudgeRoom().
565 CheckReadsThenReadStalls(audio_.get(), "50:0");
568 TEST_P(FrameProcessorTest, AudioOnly_SetOffsetThenFrameTimestampBelowOffset) {
569 // Tests A: STSO(50)+P(A20) ->
570 // if sequence mode: TSO==30,(a20@50)
571 // if segments mode: TSO==50,(a20@70)
573 AddTestTracks(HAS_AUDIO);
574 if (use_sequence_mode_)
575 frame_processor_->SetSequenceMode(true);
577 SetTimestampOffset(Milliseconds(50));
579 if (use_sequence_mode_) {
580 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
582 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(80)));
585 EXPECT_TRUE(ProcessFrames("20K", ""));
586 EXPECT_TRUE(in_coded_frame_group());
588 // We do not stall on reading without seeking to 50ms / 70ms due to
589 // SourceBufferStream::kSeekToStartFudgeRoom().
590 if (use_sequence_mode_) {
591 EXPECT_EQ(Milliseconds(30), timestamp_offset_);
592 CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) }");
593 CheckReadsThenReadStalls(audio_.get(), "50:20");
595 EXPECT_EQ(Milliseconds(50), timestamp_offset_);
596 CheckExpectedRangesByTimestamp(audio_.get(), "{ [70,80) }");
597 CheckReadsThenReadStalls(audio_.get(), "70:20");
601 TEST_P(FrameProcessorTest, AudioOnly_SequentialProcessFrames) {
602 // Tests A: P(A0,A10)+P(A20,A30) -> (a0,a10,a20,a30)
604 AddTestTracks(HAS_AUDIO);
605 if (use_sequence_mode_)
606 frame_processor_->SetSequenceMode(true);
608 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
609 EXPECT_TRUE(ProcessFrames("0K 10K", ""));
610 EXPECT_TRUE(in_coded_frame_group());
611 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
612 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
614 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
615 EXPECT_TRUE(ProcessFrames("20K 30K", ""));
616 EXPECT_TRUE(in_coded_frame_group());
617 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
618 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
620 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
623 TEST_P(FrameProcessorTest, AudioOnly_NonSequentialProcessFrames) {
624 // Tests A: P(A20,A30)+P(A0,A10) ->
625 // if sequence mode: TSO==-20 after first P(), 20 after second P(), and
626 // a(20@0,a30@10,a0@20,a10@30)
627 // if segments mode: TSO==0,(a0,a10,a20,a30)
629 AddTestTracks(HAS_AUDIO);
630 if (use_sequence_mode_) {
631 frame_processor_->SetSequenceMode(true);
632 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
634 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
637 EXPECT_TRUE(ProcessFrames("20K 30K", ""));
638 EXPECT_TRUE(in_coded_frame_group());
640 if (use_sequence_mode_) {
641 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
642 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
643 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
645 CheckExpectedRangesByTimestamp(audio_.get(), "{ [20,40) }");
646 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
647 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
650 EXPECT_TRUE(ProcessFrames("0K 10K", ""));
651 EXPECT_TRUE(in_coded_frame_group());
653 if (use_sequence_mode_) {
654 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
655 EXPECT_EQ(Milliseconds(20), timestamp_offset_);
656 CheckReadsThenReadStalls(audio_.get(), "0:20 10:30 20:0 30:10");
658 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
659 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
660 // Re-seek to 0ms now that we've appended data earlier than what has already
661 // satisfied our initial seek to start, above.
662 SeekStream(audio_.get(), Milliseconds(0));
663 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
667 TEST_P(FrameProcessorTest, AudioVideo_SequentialProcessFrames) {
668 // Tests AV: P(A0,A10;V0k,V10,V20)+P(A20,A30,A40,V30) ->
669 // (a0,a10,a20,a30,a40);(v0,v10,v20,v30)
671 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
672 if (use_sequence_mode_) {
673 frame_processor_->SetSequenceMode(true);
674 EXPECT_CALL(callbacks_,
675 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
676 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
679 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(30)));
680 EXPECT_TRUE(ProcessFrames("0K 10K", "0K 10 20"));
681 EXPECT_TRUE(in_coded_frame_group());
682 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
683 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
684 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,30) }");
686 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(50)));
687 EXPECT_TRUE(ProcessFrames("20K 30K 40K", "30"));
688 EXPECT_TRUE(in_coded_frame_group());
689 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
690 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,50) }");
691 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,40) }");
693 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30 40");
694 CheckReadsThenReadStalls(video_.get(), "0 10 20 30");
697 TEST_P(FrameProcessorTest, AudioVideo_Discontinuity) {
698 // Tests AV: P(A0,A10,A30,A40,A50;V0key,V10,V40,V50key) ->
699 // if sequence mode: TSO==10,(a0,a10,a30,a40,a50@60);(v0,v10,v50@60)
700 // if segments mode: TSO==0,(a0,a10,a30,a40,a50);(v0,v10,v50)
701 // This assumes A40K is processed before V40, which depends currently on
702 // MergeBufferQueues() behavior.
704 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
705 if (use_sequence_mode_) {
706 frame_processor_->SetSequenceMode(true);
707 EXPECT_CALL(callbacks_,
708 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
709 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
710 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(70)));
712 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
715 EXPECT_TRUE(ProcessFrames("0K 10K 30K 40K 50K", "0K 10 40 50K"));
716 EXPECT_TRUE(in_coded_frame_group());
718 if (use_sequence_mode_) {
719 EXPECT_EQ(Milliseconds(10), timestamp_offset_);
720 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,70) }");
721 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,20) [60,70) }");
722 CheckReadsThenReadStalls(audio_.get(), "0 10 30 40 60:50");
723 CheckReadsThenReadStalls(video_.get(), "0 10");
724 SeekStream(video_.get(), Milliseconds(60));
725 CheckReadsThenReadStalls(video_.get(), "60:50");
727 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
728 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,60) }");
729 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,20) [50,60) }");
730 CheckReadsThenReadStalls(audio_.get(), "0 10 30 40 50");
731 CheckReadsThenReadStalls(video_.get(), "0 10");
732 SeekStream(video_.get(), Milliseconds(50));
733 CheckReadsThenReadStalls(video_.get(), "50");
737 TEST_P(FrameProcessorTest, AudioVideo_Discontinuity_TimestampOffset) {
739 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
740 frame_processor_->SetSequenceMode(use_sequence_mode_);
741 if (use_sequence_mode_) {
742 EXPECT_CALL(callbacks_,
743 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
744 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
747 // Start a coded frame group at time 100ms. Note the jagged start still uses
748 // the coded frame group's start time as the range start for both streams.
749 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
750 SetTimestampOffset(Milliseconds(100));
751 EXPECT_TRUE(ProcessFrames("0K 10K 20K", "10K 20K 30K"));
752 EXPECT_EQ(Milliseconds(100), timestamp_offset_);
753 EXPECT_TRUE(in_coded_frame_group());
754 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
755 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) }");
757 // Test the behavior of both 'sequence' and 'segments' mode if the coded frame
758 // sequence jumps forward beyond the normal discontinuity threshold.
759 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(240)));
760 SetTimestampOffset(Milliseconds(200));
761 EXPECT_TRUE(ProcessFrames("0K 10K 20K", "10K 20K 30K"));
762 EXPECT_EQ(Milliseconds(200), timestamp_offset_);
763 EXPECT_TRUE(in_coded_frame_group());
764 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) [200,230) }");
765 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [200,240) }");
767 // Test the behavior when timestampOffset adjustment causes next frames to be
768 // in the past relative to the previously processed frame and triggers a new
769 // coded frame group.
770 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(95)));
771 SetTimestampOffset(Milliseconds(55));
772 EXPECT_TRUE(ProcessFrames("0K 10K 20K", "10K 20K 30K"));
773 EXPECT_EQ(Milliseconds(55), timestamp_offset_);
774 EXPECT_TRUE(in_coded_frame_group());
775 // The new audio range is not within SourceBufferStream's coalescing threshold
776 // relative to the next range, but the new video range is within the
778 CheckExpectedRangesByTimestamp(audio_.get(),
779 "{ [55,85) [100,130) [200,230) }");
780 // Note that the range adjacency logic used in this case considers
781 // DTS 85 to be close enough to [100,140), even though the first DTS in video
782 // range [100,140) is actually 110. The muxed data started a coded frame
783 // group at time 100, informing the adjacency logic.
784 CheckExpectedRangesByTimestamp(video_.get(), "{ [55,140) [200,240) }");
786 // Verify the buffers.
787 // Re-seek now that we've appended data earlier than what already satisfied
788 // our initial seek to start.
789 SeekStream(audio_.get(), Milliseconds(55));
790 CheckReadsThenReadStalls(audio_.get(), "55:0 65:10 75:20");
791 SeekStream(audio_.get(), Milliseconds(100));
792 CheckReadsThenReadStalls(audio_.get(), "100:0 110:10 120:20");
793 SeekStream(audio_.get(), Milliseconds(200));
794 CheckReadsThenReadStalls(audio_.get(), "200:0 210:10 220:20");
796 SeekStream(video_.get(), Milliseconds(55));
797 CheckReadsThenReadStalls(video_.get(),
798 "65:10 75:20 85:30 110:10 120:20 130:30");
799 SeekStream(video_.get(), Milliseconds(200));
800 CheckReadsThenReadStalls(video_.get(), "210:10 220:20 230:30");
803 TEST_P(FrameProcessorTest, AudioVideo_OutOfSequence_After_Discontinuity) {
804 // Once a discontinuity is detected (and all tracks drop everything until the
805 // next keyframe per each track), we should gracefully handle the case where
806 // some tracks' first keyframe after the discontinuity are appended after, but
807 // end up earlier in timeline than some other track(s). In particular, we
808 // shouldn't notify all tracks that a new coded frame group is starting and
809 // begin dropping leading non-keyframes from all tracks. Rather, we should
810 // notify just the track encountering this new type of discontinuity. Since
811 // MSE doesn't require all media segments to contain media from every track,
812 // these append sequences can occur.
814 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
815 frame_processor_->SetSequenceMode(use_sequence_mode_);
817 // Begin with a simple set of appends for all tracks.
818 if (use_sequence_mode_) {
819 // Allow room in the timeline for the last audio append (50K, below) in this
820 // test to remain within default append window [0, +Infinity]. Moving the
821 // sequence mode appends to begin at time 100ms, the same time as the first
822 // append, below, results in a -20ms offset (instead of a -120ms offset)
823 // applied to frames beginning at the first frame after the discontinuity
824 // caused by the video append at 160K, below.
825 SetTimestampOffset(Milliseconds(100));
826 EXPECT_CALL(callbacks_,
827 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
828 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
830 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
831 EXPECT_TRUE(ProcessFrames("100K 110K 120K", "110K 120K 130K"));
832 EXPECT_TRUE(in_coded_frame_group());
833 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
834 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
835 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) }");
837 // Trigger (normal) discontinuity with one track (video).
838 if (use_sequence_mode_)
839 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(150)));
841 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(170)));
843 EXPECT_TRUE(ProcessFrames("", "160K"));
844 EXPECT_TRUE(in_coded_frame_group());
846 if (use_sequence_mode_) {
847 // The new video buffer is relocated into [140,150).
848 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
849 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
850 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,150) }");
852 // The new video buffer is at [160,170).
853 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
854 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
855 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [160,170) }");
858 // Append to the other track (audio) with lower time than the video frame we
859 // just appended. Append with a timestamp such that segments mode demonstrates
860 // we don't retroactively extend the new video buffer appended above's range
861 // start back to this audio start time.
862 if (use_sequence_mode_)
863 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(150)));
865 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(170)));
867 EXPECT_TRUE(ProcessFrames("50K", ""));
868 EXPECT_TRUE(in_coded_frame_group());
870 // Because this is the first audio buffer appended following the discontinuity
871 // detected while appending the video frame, above, a new coded frame group
872 // for video is not triggered.
873 if (use_sequence_mode_) {
874 // The new audio buffer is relocated into [30,40). Note the muxed 'sequence'
875 // mode append mode results in a buffered range gap in this case.
876 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
877 CheckExpectedRangesByTimestamp(audio_.get(), "{ [30,40) [100,130) }");
878 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,150) }");
880 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
881 CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) [100,130) }");
882 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [160,170) }");
885 // Finally, append a non-keyframe to the first track (video), to continue the
886 // GOP that started the normal discontinuity on the previous video append.
887 if (use_sequence_mode_)
888 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(160)));
890 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(180)));
892 EXPECT_TRUE(ProcessFrames("", "170"));
893 EXPECT_TRUE(in_coded_frame_group());
895 // Verify the final buffers. First, re-seek audio since we appended data
896 // earlier than what already satisfied our initial seek to start. We satisfy
897 // the seek with the first buffer in [0,1000).
898 SeekStream(audio_.get(), Milliseconds(0));
899 if (use_sequence_mode_) {
900 // The new video buffer is relocated into [150,160).
901 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
902 CheckExpectedRangesByTimestamp(audio_.get(), "{ [30,40) [100,130) }");
903 CheckReadsThenReadStalls(audio_.get(), "30:50");
904 SeekStream(audio_.get(), Milliseconds(100));
905 CheckReadsThenReadStalls(audio_.get(), "100 110 120");
907 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,160) }");
908 CheckReadsThenReadStalls(video_.get(), "110 120 130 140:160 150:170");
910 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
911 CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) [100,130) }");
912 CheckReadsThenReadStalls(audio_.get(), "50");
913 SeekStream(audio_.get(), Milliseconds(100));
914 CheckReadsThenReadStalls(audio_.get(), "100 110 120");
916 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [160,180) }");
917 CheckReadsThenReadStalls(video_.get(), "110 120 130");
918 SeekStream(video_.get(), Milliseconds(160));
919 CheckReadsThenReadStalls(video_.get(), "160 170");
923 TEST_P(FrameProcessorTest,
924 AppendWindowFilterOfNegativeBufferTimestampsWithPrerollDiscard) {
926 AddTestTracks(HAS_AUDIO);
927 if (use_sequence_mode_)
928 frame_processor_->SetSequenceMode(true);
930 SetTimestampOffset(Milliseconds(-20));
931 EXPECT_MEDIA_LOG(DroppedFrame("audio", -20000));
932 EXPECT_MEDIA_LOG(DroppedFrame("audio", -10000));
933 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
934 EXPECT_TRUE(ProcessFrames("0K 10K 20K", ""));
935 EXPECT_TRUE(in_coded_frame_group());
936 EXPECT_EQ(Milliseconds(-20), timestamp_offset_);
937 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) }");
938 CheckReadsThenReadStalls(audio_.get(), "0:10P 0:20");
941 TEST_P(FrameProcessorTest, AppendWindowFilterWithInexactPreroll) {
943 AddTestTracks(HAS_AUDIO);
944 if (use_sequence_mode_)
945 frame_processor_->SetSequenceMode(true);
946 SetTimestampOffset(Milliseconds(-10));
947 EXPECT_MEDIA_LOG(DroppedFrame("audio", -10000));
948 EXPECT_MEDIA_LOG(TruncatedFrame(-250, 9750, "start", 0));
949 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
950 EXPECT_TRUE(ProcessFrames("0K 9.75K 20K", ""));
951 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
952 CheckReadsThenReadStalls(audio_.get(), "0P 0:9.75 10:20");
955 TEST_P(FrameProcessorTest, AppendWindowFilterWithInexactPreroll_2) {
957 AddTestTracks(HAS_AUDIO);
958 if (use_sequence_mode_)
959 frame_processor_->SetSequenceMode(true);
960 SetTimestampOffset(Milliseconds(-10));
962 EXPECT_MEDIA_LOG(DroppedFrame("audio", -10000));
963 // Splice trimming checks are done on every audio frame following either a
964 // discontinuity or the beginning of ProcessFrames(), and are also done on
965 // audio frames with PTS not directly continuous with the highest frame end
966 // PTS already processed.
967 if (use_sequence_mode_)
968 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(-10)));
970 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(0)));
971 EXPECT_TRUE(ProcessFrames("0K", ""));
973 EXPECT_CALL(callbacks_, PossibleDurationIncrease(base::Microseconds(10250)));
974 EXPECT_TRUE(ProcessFrames("10.25K", ""));
976 EXPECT_MEDIA_LOG(SkippingSpliceTooLittleOverlap(10000, 250));
977 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
978 EXPECT_TRUE(ProcessFrames("20K", ""));
980 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
981 CheckReadsThenReadStalls(audio_.get(), "0P 0:10.25 10:20");
984 TEST_P(FrameProcessorTest, AllowNegativeFramePTSAndDTSBeforeOffsetAdjustment) {
986 AddTestTracks(HAS_AUDIO);
987 if (use_sequence_mode_) {
988 frame_processor_->SetSequenceMode(true);
989 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(30)));
991 EXPECT_MEDIA_LOG(TruncatedFrame(-5000, 5000, "start", 0));
992 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(25)));
995 EXPECT_TRUE(ProcessFrames("-5K 5K 15K", ""));
997 if (use_sequence_mode_) {
998 EXPECT_EQ(Milliseconds(5), timestamp_offset_);
999 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,30) }");
1000 CheckReadsThenReadStalls(audio_.get(), "0:-5 10:5 20:15");
1002 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1003 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,25) }");
1004 CheckReadsThenReadStalls(audio_.get(), "0:-5 5 15");
1008 TEST_P(FrameProcessorTest, PartialAppendWindowFilterNoDiscontinuity) {
1009 // Tests that spurious discontinuity is not introduced by a partially
1011 append_window_start_ = Milliseconds(7);
1014 AddTestTracks(HAS_AUDIO);
1015 if (use_sequence_mode_)
1016 frame_processor_->SetSequenceMode(true);
1017 EXPECT_MEDIA_LOG(TruncatedFrame(0, 10000, "start", 7000));
1018 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(29)));
1020 EXPECT_TRUE(ProcessFrames("0K 19K", ""));
1022 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1023 CheckExpectedRangesByTimestamp(audio_.get(), "{ [7,29) }");
1024 CheckReadsThenReadStalls(audio_.get(), "7:0 19");
1027 TEST_P(FrameProcessorTest,
1028 PartialAppendWindowFilterNoDiscontinuity_DtsAfterPts) {
1029 // Tests that spurious discontinuity is not introduced by a partially trimmed
1030 // frame that originally had DTS > PTS.
1032 AddTestTracks(HAS_AUDIO);
1034 if (use_sequence_mode_) {
1035 frame_processor_->SetSequenceMode(true);
1036 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
1038 EXPECT_MEDIA_LOG(TruncatedFrame(-7000, 3000, "start", 0));
1039 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(13)));
1042 // Process a sequence of two audio frames:
1043 // A: PTS -7ms, DTS 10ms, duration 10ms, keyframe
1044 // B: PTS 3ms, DTS 20ms, duration 10ms, keyframe
1045 EXPECT_TRUE(ProcessFrames("-7|10K 3|20K", ""));
1047 if (use_sequence_mode_) {
1048 // Sequence mode detected that frame A needs to be relocated 7ms into the
1049 // future to begin the sequence at time 0. There is no append window
1050 // filtering because the PTS result of the relocation is within the append
1051 // window of [0,+Infinity).
1052 // Frame A is relocated by 7 to PTS 0, DTS 17, duration 10.
1053 // Frame B is relocated by 7 to PTS 10, DTS 27, duration 10.
1054 EXPECT_EQ(Milliseconds(7), timestamp_offset_);
1056 // Start of frame A (0) through end of frame B (10+10).
1057 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
1059 // Frame A is now at PTS 0 (originally at PTS -7)
1060 // Frame B is now at PTS 10 (originally at PTS 3)
1061 CheckReadsThenReadStalls(audio_.get(), "0:-7 10:3");
1063 // Segments mode does not update timestampOffset automatically, so it
1064 // remained 0 and neither frame was relocated by timestampOffset.
1065 // Frame A's start *was* relocated by append window partial audio cropping:
1066 // Append window filtering (done by PTS, regardless of range buffering API)
1067 // did a partial crop of the first 7ms of frame A which was before
1068 // the default append window start time 0, and moved both the PTS and DTS of
1069 // frame A forward by 7 and reduced its duration by 7. Frame B was fully
1070 // inside the append window and remained uncropped and unrelocated.
1071 // Frame A is buffered at PTS -7+7=0, DTS 10+7=17, duration 10-7=3.
1072 // Frame B is buffered at PTS 3, DTS 20, duration 10.
1073 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1075 // Start of frame A (0) through end of frame B (3+10).
1076 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,13) }");
1078 // Frame A is now at PTS 0 (originally at PTS -7)
1079 // Frame B is now at PTS 3 (same as it was originally)
1080 CheckReadsThenReadStalls(audio_.get(), "0:-7 3");
1084 TEST_P(FrameProcessorTest, PartialAppendWindowFilterNoNewMediaSegment) {
1085 // Tests that a new media segment is not forcibly signalled for audio frame
1086 // partial front trim, to prevent incorrect introduction of a discontinuity
1087 // and potentially a non-keyframe video frame to be processed next after the
1090 AddTestTracks(HAS_AUDIO | HAS_VIDEO);
1091 frame_processor_->SetSequenceMode(use_sequence_mode_);
1092 if (use_sequence_mode_) {
1093 EXPECT_CALL(callbacks_,
1094 OnParseWarning(SourceBufferParseWarning::kMuxedSequenceMode));
1095 EXPECT_MEDIA_LOG(MuxedSequenceModeWarning());
1097 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1098 EXPECT_TRUE(ProcessFrames("", "0K"));
1099 EXPECT_MEDIA_LOG(TruncatedFrame(-5000, 5000, "start", 0));
1100 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1101 EXPECT_TRUE(ProcessFrames("-5K", ""));
1102 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
1103 EXPECT_TRUE(ProcessFrames("", "10"));
1105 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1106 EXPECT_TRUE(in_coded_frame_group());
1107 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,5) }");
1108 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,20) }");
1109 CheckReadsThenReadStalls(audio_.get(), "0:-5");
1110 CheckReadsThenReadStalls(video_.get(), "0 10");
1113 TEST_P(FrameProcessorTest, AudioOnly_SequenceModeContinuityAcrossReset) {
1114 if (!use_sequence_mode_) {
1115 DVLOG(1) << "Skipping segments mode variant; inapplicable to this case.";
1120 AddTestTracks(HAS_AUDIO);
1121 frame_processor_->SetSequenceMode(true);
1122 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1123 EXPECT_TRUE(ProcessFrames("0K", ""));
1124 frame_processor_->Reset();
1125 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
1126 EXPECT_TRUE(ProcessFrames("100K", ""));
1128 EXPECT_EQ(Milliseconds(-90), timestamp_offset_);
1129 EXPECT_TRUE(in_coded_frame_group());
1130 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
1131 CheckReadsThenReadStalls(audio_.get(), "0 10:100");
1134 TEST_P(FrameProcessorTest, PartialAppendWindowZeroDurationPreroll) {
1136 AddTestTracks(HAS_AUDIO);
1137 frame_processor_->SetSequenceMode(use_sequence_mode_);
1139 append_window_start_ = Milliseconds(5);
1141 EXPECT_MEDIA_LOG(DroppedFrame("audio", use_sequence_mode_ ? 0 : 4000));
1142 // Append a 0 duration frame that falls just before the append window.
1143 frame_duration_ = Milliseconds(0);
1144 EXPECT_FALSE(in_coded_frame_group());
1145 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(0)));
1146 EXPECT_TRUE(ProcessFrames("4K", ""));
1147 // Verify buffer is not part of ranges. It should be silently saved for
1148 // preroll for future append.
1149 CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
1150 CheckReadsThenReadStalls(audio_.get(), "");
1151 EXPECT_FALSE(in_coded_frame_group());
1153 // Abort the reads from last stall. We don't want those reads to "complete"
1154 // when we append below. We will initiate new reads to confirm the buffer
1155 // looks as we expect.
1156 SeekStream(audio_.get(), Milliseconds(0));
1158 if (use_sequence_mode_) {
1159 EXPECT_MEDIA_LOG(TruncatedFrame(0, 10000, "start", 5000));
1161 EXPECT_MEDIA_LOG(TruncatedFrame(4000, 14000, "start", 5000));
1163 // Append a frame with 10ms duration, with 9ms falling after the window start.
1164 EXPECT_CALL(callbacks_, PossibleDurationIncrease(
1165 Milliseconds(use_sequence_mode_ ? 10 : 14)));
1166 frame_duration_ = Milliseconds(10);
1167 EXPECT_TRUE(ProcessFrames("4K", ""));
1168 EXPECT_TRUE(in_coded_frame_group());
1170 // Verify range updated to reflect last append was processed and trimmed, and
1171 // also that zero duration buffer was saved and attached as preroll.
1172 if (use_sequence_mode_) {
1173 // For sequence mode, append window trimming is applied after the append
1174 // is adjusted for timestampOffset. Basically, everything gets rebased to 0
1175 // and trimming then removes 5 seconds from the front.
1176 CheckExpectedRangesByTimestamp(audio_.get(), "{ [5,10) }");
1177 CheckReadsThenReadStalls(audio_.get(), "5:4P 5:4");
1178 } else { // segments mode
1179 CheckExpectedRangesByTimestamp(audio_.get(), "{ [5,14) }");
1180 CheckReadsThenReadStalls(audio_.get(), "5:4P 5:4");
1183 // Verify the preroll buffer still has zero duration.
1184 StreamParserBuffer* last_read_parser_buffer =
1185 static_cast<StreamParserBuffer*>(last_read_buffer_.get());
1186 ASSERT_EQ(Milliseconds(0),
1187 last_read_parser_buffer->preroll_buffer()->duration());
1190 TEST_P(FrameProcessorTest,
1191 OOOKeyframePrecededByDependantNonKeyframeShouldWarn) {
1193 AddTestTracks(HAS_VIDEO);
1194 frame_processor_->SetSequenceMode(use_sequence_mode_);
1196 if (use_sequence_mode_) {
1197 // Allow room in the timeline for the last video append (40|70, below) in
1198 // this test to remain within default append window [0, +Infinity]. Moving
1199 // the sequence mode appends to begin at time 50ms, the same time as the
1200 // first append, below, also results in identical expectation checks for
1201 // buffered ranges and buffer reads for both segments and sequence modes.
1202 SetTimestampOffset(Milliseconds(50));
1205 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(70)));
1206 EXPECT_TRUE(ProcessFrames("", "50K 60"));
1208 CheckExpectedRangesByTimestamp(video_.get(), "{ [50,70) }");
1210 EXPECT_CALL(callbacks_,
1212 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1213 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.05", "0.04"));
1214 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(70)));
1215 EXPECT_TRUE(ProcessFrames("", "40|70")); // PTS=40, DTS=70
1217 // This reflects the expectation that PTS start is not "pulled backward" for
1218 // the new frame at PTS=40 because current spec doesn't support SAP Type 2; it
1219 // has no steps in the coded frame processing algorithm that would do that
1220 // "pulling backward". See https://github.com/w3c/media-source/issues/187.
1221 CheckExpectedRangesByTimestamp(video_.get(), "{ [50,70) }");
1223 SeekStream(video_.get(), Milliseconds(0));
1224 CheckReadsThenReadStalls(video_.get(), "50 60 40");
1227 TEST_P(FrameProcessorTest, OOOKeyframePts_1) {
1229 AddTestTracks(HAS_AUDIO);
1230 frame_processor_->SetSequenceMode(use_sequence_mode_);
1232 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1010)));
1233 // Note that the following does not contain a DTS continuity, but *does*
1234 // contain a PTS discontinuity (keyframe at 0.1s after keyframe at 1s).
1235 EXPECT_TRUE(ProcessFrames("0K 1000|10K 100|20K", ""));
1237 // Force sequence mode to place the next frames where segments mode would put
1238 // them, to simplify this test case.
1239 if (use_sequence_mode_)
1240 SetTimestampOffset(Milliseconds(500));
1242 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(510)));
1243 EXPECT_TRUE(ProcessFrames("500|100K", ""));
1244 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1246 // Note that the PTS discontinuity (100ms) in the first ProcessFrames() call,
1247 // above, overlaps the previously buffered range [0,1010), so the frame at
1248 // 100ms is processed with an adjusted coded frame group start to be 0.001ms,
1249 // which is just after the highest timestamp before it in the overlapped
1250 // range. This enables it to be continuous with the frame before it. The
1251 // remainder of the overlapped range (the buffer at [1000,1010)) is adjusted
1252 // to have a range start time at the split point (110), and is within fudge
1253 // room and merged into [0,110). The same happens with the buffer appended
1255 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,1010) }");
1256 CheckReadsThenReadStalls(audio_.get(), "0 100 500 1000");
1259 TEST_P(FrameProcessorTest, OOOKeyframePts_2) {
1261 AddTestTracks(HAS_AUDIO);
1262 frame_processor_->SetSequenceMode(use_sequence_mode_);
1264 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1010)));
1265 EXPECT_TRUE(ProcessFrames("0K 1000|10K", ""));
1267 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1010)));
1268 EXPECT_TRUE(ProcessFrames("100|20K", ""));
1270 // Note that the PTS discontinuity (100ms) in the first ProcessFrames() call,
1271 // above, overlaps the previously buffered range [0,1010), so the frame at
1272 // 100ms is processed with an adjusted coded frame group start to be 0.001ms,
1273 // which is just after the highest timestamp before it in the overlapped
1274 // range. This enables it to be continuous with the frame before it. The
1275 // remainder of the overlapped range (the buffer at [1000,1010)) is adjusted
1276 // to have a range start time at the split point (110), and is within fudge
1277 // room and merged into [0,110).
1278 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,1010) }");
1279 CheckReadsThenReadStalls(audio_.get(), "0 100 1000");
1282 TEST_P(FrameProcessorTest, AudioNonKeyframeChangedToKeyframe) {
1283 // Verifies that an audio non-keyframe is changed to a keyframe with a media
1284 // log warning. An exact overlap append of the preceding keyframe is also done
1285 // to ensure that the (original non-keyframe) survives (because it was changed
1286 // to a keyframe, so no longer depends on the original preceding keyframe).
1287 // The sequence mode test version uses SetTimestampOffset to make it behave
1288 // like segments mode to simplify the tests.
1289 // Note, see the NonkeyframeAudioBuffering tests to verify buffering of audio
1290 // nonkeyframes for codec(s) that use nonkeyframes.
1292 AddTestTracks(HAS_AUDIO);
1293 frame_processor_->SetSequenceMode(use_sequence_mode_);
1295 EXPECT_MEDIA_LOG(AudioNonKeyframe(10000, 10000));
1296 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(30)));
1297 EXPECT_TRUE(ProcessFrames("0K 10 20K", ""));
1299 if (use_sequence_mode_)
1300 SetTimestampOffset(Milliseconds(0));
1302 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1303 EXPECT_TRUE(ProcessFrames("0K", ""));
1305 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,30) }");
1306 SeekStream(audio_.get(), Milliseconds(0));
1307 CheckReadsThenReadStalls(audio_.get(), "0 10 20");
1310 TEST_P(FrameProcessorTest, TimestampOffsetNegativeDts) {
1311 // Shift a GOP earlier using timestampOffset such that the GOP
1312 // starts with negative DTS, but PTS 0.
1314 AddTestTracks(HAS_VIDEO);
1315 frame_processor_->SetSequenceMode(use_sequence_mode_);
1317 if (!use_sequence_mode_) {
1318 // Simulate the offset that sequence mode would apply, to make the results
1319 // the same regardless of sequence vs segments mode.
1320 SetTimestampOffset(Milliseconds(-100));
1323 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
1324 EXPECT_TRUE(ProcessFrames("", "100|70K 130|80"));
1325 EXPECT_EQ(Milliseconds(-100), timestamp_offset_);
1326 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,40) }");
1327 SeekStream(video_.get(), Milliseconds(0));
1328 CheckReadsThenReadStalls(video_.get(), "0:100 30:130");
1331 TEST_P(FrameProcessorTest, LargeTimestampOffsetJumpForward) {
1332 // Verifies that jumps forward in buffers emitted from the coded frame
1333 // processing algorithm can create discontinuous buffered ranges if those
1334 // jumps are large enough, in both kinds of AppendMode.
1336 AddTestTracks(HAS_AUDIO);
1337 frame_processor_->SetSequenceMode(use_sequence_mode_);
1339 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
1340 EXPECT_TRUE(ProcessFrames("0K", ""));
1342 SetTimestampOffset(Milliseconds(5000));
1344 // Along with the new timestampOffset set above, this should cause a large
1345 // jump forward in both PTS and DTS for both sequence and segments append
1347 if (use_sequence_mode_) {
1348 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(5010)));
1350 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10010)));
1352 EXPECT_TRUE(ProcessFrames("5000|100K", ""));
1353 if (use_sequence_mode_) {
1354 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1356 EXPECT_EQ(Milliseconds(5000), timestamp_offset_);
1359 if (use_sequence_mode_) {
1360 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) [5000,5010) }");
1361 CheckReadsThenReadStalls(audio_.get(), "0");
1362 SeekStream(audio_.get(), Milliseconds(5000));
1363 CheckReadsThenReadStalls(audio_.get(), "5000");
1365 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) [10000,10010) }");
1366 CheckReadsThenReadStalls(audio_.get(), "0");
1367 SeekStream(audio_.get(), Milliseconds(10000));
1368 CheckReadsThenReadStalls(audio_.get(), "10000:5000");
1372 TEST_P(FrameProcessorTest, ContinuousDts_SapType2_and_PtsJumpForward) {
1374 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1375 frame_processor_->SetSequenceMode(use_sequence_mode_);
1377 // Make the sequence mode buffering appear just like segments mode to simplify
1379 if (use_sequence_mode_)
1380 SetTimestampOffset(Milliseconds(1060));
1382 // Note that the PTS of GOP non-keyframes earlier than the keyframe doesn't
1383 // modify the GOP start of the buffered range here. This may change if we
1384 // decide to improve spec for SAP Type 2 GOPs that begin a coded frame group.
1385 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1386 Milliseconds(1060)));
1387 EXPECT_CALL(callbacks_,
1389 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1390 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("1.06", "1"));
1391 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1392 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1393 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1070)));
1394 EXPECT_TRUE(ProcessFrames(
1395 "", "1060|0K 1000|10 1050|20 1010|30 1040|40 1020|50 1030|60"));
1396 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1397 CheckExpectedRangesByTimestamp(video_.get(), "{ [1060,1070) }");
1399 // Process just the keyframe of the next SAP Type 2 GOP in decode continuity
1400 // with the previous one.
1401 // Note that this second GOP is buffered continuous with the first because
1402 // there is no decode discontinuity detected. This results in inclusion of
1403 // the significant PTS jump forward in the same continuous range.
1406 OnGroupStart(DemuxerStream::VIDEO,
1407 DecodeTimestamp::FromPresentationTime(Milliseconds(60)),
1408 Milliseconds(1070)));
1409 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1410 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1140)));
1411 EXPECT_TRUE(ProcessFrames("", "1130|70K"));
1412 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1413 CheckExpectedRangesByTimestamp(video_.get(), "{ [1060,1140) }");
1415 // Process the remainder of the second GOP.
1416 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1417 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(1140)));
1419 ProcessFrames("", "1070|80 1120|90 1080|100 1110|110 1090|120 1100|130"));
1420 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1421 CheckExpectedRangesByTimestamp(video_.get(), "{ [1060,1140) }");
1423 // [1060,1140) should demux continuously without read stall in the middle.
1424 SeekStream(video_.get(), Milliseconds(1060));
1425 CheckReadsThenReadStalls(
1427 "1060 1000 1050 1010 1040 1020 1030 1130 1070 1120 1080 1110 1090 1100");
1428 // Verify that seek and read of the second GOP is correct.
1429 SeekStream(video_.get(), Milliseconds(1130));
1430 CheckReadsThenReadStalls(video_.get(), "1130 1070 1120 1080 1110 1090 1100");
1433 TEST_P(FrameProcessorTest, ContinuousDts_NewGopEndOverlapsLastGop_1) {
1434 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1435 // PTS interval overlapping the previous append.
1436 // Tests SAP-Type-1 GOPs, where newly appended GOP overlaps a nonkeyframe of
1437 // the last GOP appended.
1439 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1440 frame_processor_->SetSequenceMode(use_sequence_mode_);
1442 // Make the sequence mode buffering appear just like segments mode to simplify
1444 if (use_sequence_mode_)
1445 SetTimestampOffset(Milliseconds(100));
1447 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1448 Milliseconds(100)));
1449 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1450 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
1451 EXPECT_TRUE(ProcessFrames("", "100|0K 110|10 120|20 130|30"));
1452 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1456 OnGroupStart(DemuxerStream::VIDEO,
1457 DecodeTimestamp::FromPresentationTime(Milliseconds(30)),
1458 Milliseconds(125)));
1459 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1460 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(165)));
1461 EXPECT_TRUE(ProcessFrames("", "125|40K 135|50 145|60 155|70"));
1462 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1464 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,165) }");
1465 CheckReadsThenReadStalls(video_.get(), "100 110 120 125 135 145 155");
1468 TEST_P(FrameProcessorTest, ContinuousDts_NewGopEndOverlapsLastGop_2) {
1469 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1470 // PTS interval overlapping the previous append.
1471 // Tests SAP-Type 1 GOPs, where newly appended GOP overlaps the keyframe of
1472 // the last GOP appended.
1474 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1475 frame_processor_->SetSequenceMode(use_sequence_mode_);
1477 // Make the sequence mode buffering appear just like segments mode to simplify
1479 if (use_sequence_mode_)
1480 SetTimestampOffset(Milliseconds(100));
1482 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1483 Milliseconds(100)));
1484 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1485 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
1486 EXPECT_TRUE(ProcessFrames("", "100|0K 110|10 120|20K 130|30"));
1487 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1491 OnGroupStart(DemuxerStream::VIDEO,
1492 DecodeTimestamp::FromPresentationTime(Milliseconds(30)),
1493 Milliseconds(115)));
1494 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1495 // TODO(wolenetz): Duration shouldn't be allowed to possibly increase to 140ms
1496 // here. See https://crbug.com/763620.
1497 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
1498 EXPECT_TRUE(ProcessFrames("", "115|40K 125|50"));
1499 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1501 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,135) }");
1502 CheckReadsThenReadStalls(video_.get(), "100 110 115 125");
1505 TEST_P(FrameProcessorTest, ContinuousDts_NewSap2GopEndOverlapsLastGop_1) {
1506 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1507 // PTS interval overlapping the previous append, using SAP Type 2 GOPs.
1508 // Tests SAP-Type 2 GOPs, where newly appended GOP overlaps nonkeyframes of
1509 // the last GOP appended.
1511 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1512 frame_processor_->SetSequenceMode(use_sequence_mode_);
1514 // Make the sequence mode buffering appear just like segments mode to simplify
1516 if (use_sequence_mode_)
1517 SetTimestampOffset(Milliseconds(120));
1519 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1520 Milliseconds(120)));
1521 EXPECT_CALL(callbacks_,
1523 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1524 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.12", "0.1"));
1525 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1526 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1527 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(140)));
1528 EXPECT_TRUE(ProcessFrames("", "120|0K 100|10 130|20 110|30"));
1529 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1531 // Note, we *don't* expect another OnGroupStart during the next ProcessFrames,
1532 // since the next GOP's keyframe PTS is after the first GOP and close enough
1533 // to be assured adjacent.
1534 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1535 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1536 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(165)));
1537 EXPECT_TRUE(ProcessFrames("", "145|40K 125|50 155|60 135|70"));
1538 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1540 CheckExpectedRangesByTimestamp(video_.get(), "{ [120,165) }");
1541 // [120,165) should demux continuously without read stall in the middle.
1542 CheckReadsThenReadStalls(video_.get(), "120 100 130 110 145 125 155 135");
1543 // Verify that seek and read of the second GOP is correct.
1544 SeekStream(video_.get(), Milliseconds(145));
1545 CheckReadsThenReadStalls(video_.get(), "145 125 155 135");
1548 TEST_P(FrameProcessorTest, ContinuousDts_NewSap2GopEndOverlapsLastGop_2) {
1549 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1550 // PTS interval overlapping the previous append, using SAP Type 2 GOPs.
1551 // Tests SAP-Type 2 GOPs, where newly appended GOP overlaps the keyframe of
1552 // last GOP appended.
1554 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1555 frame_processor_->SetSequenceMode(use_sequence_mode_);
1557 // Make the sequence mode buffering appear just like segments mode to simplify
1559 if (use_sequence_mode_)
1560 SetTimestampOffset(Milliseconds(120));
1562 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1563 Milliseconds(120)));
1564 EXPECT_CALL(callbacks_,
1566 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1567 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.12", "0.1"));
1568 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1569 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1570 // There is a second GOP that is SAP-Type-2 within this first ProcessFrames,
1571 // with PTS jumping forward far enough to trigger group start signalling and a
1575 OnGroupStart(DemuxerStream::VIDEO,
1576 DecodeTimestamp::FromPresentationTime(Milliseconds(30)),
1577 Milliseconds(140)));
1578 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1579 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(180)));
1580 EXPECT_TRUE(ProcessFrames(
1581 "", "120|0K 100|10 130|20 110|30 160|40K 140|50 170|60 150|70"));
1582 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1586 OnGroupStart(DemuxerStream::VIDEO,
1587 DecodeTimestamp::FromPresentationTime(Milliseconds(70)),
1588 Milliseconds(155)));
1589 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1590 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1591 // TODO(wolenetz): Duration shouldn't be allowed to possibly increase to 180ms
1592 // here. See https://crbug.com/763620.
1593 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(180)));
1594 EXPECT_TRUE(ProcessFrames("", "155|80K 145|90"));
1595 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1597 CheckExpectedRangesByTimestamp(video_.get(), "{ [120,165) }");
1598 // [120,165) should demux continuously without read stall in the middle.
1599 CheckReadsThenReadStalls(video_.get(), "120 100 130 110 155 145");
1600 // Verify seek and read of the second GOP is correct.
1601 SeekStream(video_.get(), Milliseconds(155));
1602 CheckReadsThenReadStalls(video_.get(), "155 145");
1605 TEST_P(FrameProcessorTest,
1606 ContinuousDts_NewSap2GopEndOverlapsLastGop_3_GopByGop) {
1607 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1608 // PTS interval overlapping the previous append, using SAP Type 2 GOPs. Tests
1609 // SAP-Type 2 GOPs, where newly appended GOP overlaps enough nonkeyframes of
1610 // the previous GOP such that dropped decode dependencies might cause problems
1611 // if the first nonkeyframe with PTS prior to the GOP's keyframe PTS is
1612 // flushed at the same time as its keyframe, but the second GOP's keyframe PTS
1613 // is close enough to the end of the first GOP's presentation interval to not
1614 // signal a new coded frame group start.
1616 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1617 frame_processor_->SetSequenceMode(use_sequence_mode_);
1619 // Make the sequence mode buffering appear just like segments mode to simplify
1621 if (use_sequence_mode_)
1622 SetTimestampOffset(Milliseconds(500));
1624 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1625 Milliseconds(500)));
1626 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1627 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(530)));
1628 EXPECT_TRUE(ProcessFrames("", "500|0K 520|10 510|20"));
1629 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,530) }");
1631 EXPECT_CALL(callbacks_,
1633 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1634 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.54", "0.52"));
1635 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1636 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1637 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(550)));
1638 EXPECT_TRUE(ProcessFrames("", "540|30K 520|40 530|50"));
1640 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,550) }");
1641 SeekStream(video_.get(), Milliseconds(500));
1642 CheckReadsThenReadStalls(video_.get(), "500 520 510 540 520 530");
1645 TEST_P(FrameProcessorTest,
1646 ContinuousDts_NewSap2GopEndOverlapsLastGop_3_FrameByFrame) {
1647 // Tests that the buffered range results match the previous GopByGop test if
1648 // each frame of the second GOP is explicitly appended by the app
1651 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1652 frame_processor_->SetSequenceMode(use_sequence_mode_);
1654 // Make the sequence mode buffering appear just like segments mode to simplify
1656 if (use_sequence_mode_)
1657 SetTimestampOffset(Milliseconds(500));
1659 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1660 Milliseconds(500)));
1661 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1662 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(530)));
1663 EXPECT_TRUE(ProcessFrames("", "500|0K 520|10 510|20"));
1664 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,530) }");
1666 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1667 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(550)));
1668 EXPECT_TRUE(ProcessFrames("", "540|30K"));
1670 EXPECT_CALL(callbacks_,
1672 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1673 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.54", "0.52"));
1674 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1675 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(550)));
1676 EXPECT_TRUE(ProcessFrames("", "520|40"));
1678 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1679 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(550)));
1680 EXPECT_TRUE(ProcessFrames("", "530|50"));
1682 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,550) }");
1683 SeekStream(video_.get(), Milliseconds(500));
1684 CheckReadsThenReadStalls(video_.get(), "500 520 510 540 520 530");
1687 TEST_P(FrameProcessorTest,
1688 ContinuousDts_NewSap2GopEndOverlapsLastGop_4_GopByGop) {
1689 // API user might craft a continuous-in-DTS-with-previous-append GOP that has
1690 // PTS interval overlapping the previous append, using SAP Type 2 GOPs. Tests
1691 // SAP-Type 2 GOPs, where newly appended GOP overlaps enough nonkeyframes of
1692 // the previous GOP such that dropped decode dependencies might cause problems
1693 // if the first nonkeyframe with PTS prior to the GOP's keyframe PTS is
1694 // flushed at the same time as its keyframe.
1696 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1697 frame_processor_->SetSequenceMode(use_sequence_mode_);
1699 // Make the sequence mode buffering appear just like segments mode to simplify
1701 if (use_sequence_mode_)
1702 SetTimestampOffset(Milliseconds(500));
1704 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1705 Milliseconds(500)));
1706 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1707 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(530)));
1708 EXPECT_TRUE(ProcessFrames("", "500|0K 520|10 510|20"));
1709 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,530) }");
1713 OnGroupStart(DemuxerStream::VIDEO,
1714 DecodeTimestamp::FromPresentationTime(Milliseconds(20)),
1715 Milliseconds(530)));
1716 EXPECT_CALL(callbacks_,
1718 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1719 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.55", "0.52"));
1720 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1721 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1722 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1723 EXPECT_TRUE(ProcessFrames("", "550|30K 520|40 530|50 540|60"));
1725 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,560) }");
1726 SeekStream(video_.get(), Milliseconds(500));
1727 CheckReadsThenReadStalls(video_.get(), "500 520 510 550 520 530 540");
1730 TEST_P(FrameProcessorTest,
1731 ContinuousDts_NewSap2GopEndOverlapsLastGop_4_FrameByFrame) {
1732 // Tests that the buffered range results match the previous GopByGop test if
1733 // each frame of the second GOP is explicitly appended by the app
1736 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1737 frame_processor_->SetSequenceMode(use_sequence_mode_);
1739 // Make the sequence mode buffering appear just like segments mode to simplify
1741 if (use_sequence_mode_)
1742 SetTimestampOffset(Milliseconds(500));
1744 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1745 Milliseconds(500)));
1746 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1747 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(530)));
1748 EXPECT_TRUE(ProcessFrames("", "500|0K 520|10 510|20"));
1749 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,530) }");
1753 OnGroupStart(DemuxerStream::VIDEO,
1754 DecodeTimestamp::FromPresentationTime(Milliseconds(20)),
1755 Milliseconds(530)));
1756 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1757 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1758 EXPECT_TRUE(ProcessFrames("", "550|30K"));
1760 EXPECT_CALL(callbacks_,
1762 SourceBufferParseWarning::kKeyframeTimeGreaterThanDependant));
1763 EXPECT_MEDIA_LOG(KeyframeTimeGreaterThanDependant("0.55", "0.52"));
1764 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1765 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1766 EXPECT_TRUE(ProcessFrames("", "520|40"));
1768 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1769 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1770 EXPECT_TRUE(ProcessFrames("", "530|50"));
1772 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1773 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(560)));
1774 EXPECT_TRUE(ProcessFrames("", "540|60"));
1776 CheckExpectedRangesByTimestamp(video_.get(), "{ [500,560) }");
1777 SeekStream(video_.get(), Milliseconds(500));
1778 CheckReadsThenReadStalls(video_.get(), "500 520 510 550 520 530 540");
1781 TEST_P(FrameProcessorTest, ContinuousDts_GopKeyframePtsOrder_2_1_3) {
1782 // White-box test, demonstrating expected behavior for a specially crafted
1783 // sequence that "should" be unusual, but gracefully handled:
1784 // SAP-Type 1 GOPs for simplicity of test. First appended GOP is highest in
1785 // timeline. Second appended GOP is earliest in timeline. Third appended GOP
1786 // is continuous in time with highest end time of first appended GOP. The
1787 // result should be a single continuous range containing just the second and
1788 // third appended GOPs (since the first-appended GOP was overlap-removed from
1789 // the timeline due to being in the gap between the second and third appended
1790 // GOPs). Note that MseTrackBuffer::ResetHighestPresentationTimestamp() done
1791 // at the beginning of the second appended GOP is the key to gracefully
1792 // handling the third appended GOP.
1794 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1795 frame_processor_->SetSequenceMode(use_sequence_mode_);
1797 // Make the sequence mode buffering appear just like segments mode to simplify
1799 if (use_sequence_mode_)
1800 SetTimestampOffset(Milliseconds(200));
1802 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::VIDEO, DecodeTimestamp(),
1803 Milliseconds(200)));
1804 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1805 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(240)));
1806 EXPECT_TRUE(ProcessFrames("", "200|0K 210|10 220|20 230|30"));
1807 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1808 CheckExpectedRangesByTimestamp(video_.get(), "{ [200,240) }");
1812 OnGroupStart(DemuxerStream::VIDEO,
1813 DecodeTimestamp::FromPresentationTime(Milliseconds(30)),
1814 Milliseconds(100)));
1815 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1816 // TODO(wolenetz): Duration shouldn't be allowed to possibly increase to 240ms
1817 // here. See https://crbug.com/763620.
1818 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(240)));
1819 EXPECT_TRUE(ProcessFrames("", "100|40K 110|50 120|60 130|70"));
1820 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1821 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,140) [200,240) }");
1825 OnGroupStart(DemuxerStream::VIDEO,
1826 DecodeTimestamp::FromPresentationTime(Milliseconds(70)),
1827 Milliseconds(140)));
1828 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1829 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(260)));
1830 EXPECT_TRUE(ProcessFrames("", "240|80K 250|90"));
1831 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1832 CheckExpectedRangesByTimestamp(video_.get(), "{ [100,260) }");
1834 SeekStream(video_.get(), Milliseconds(100));
1835 CheckReadsThenReadStalls(video_.get(), "100 110 120 130 240 250");
1838 TEST_P(FrameProcessorTest, ContinuousPts_DiscontinuousDts_AcrossGops) {
1839 // GOPs which overlap in DTS, but are continuous in PTS should be buffered
1840 // correctly. In particular, monotonic increase of DTS in continuous-in-PTS
1841 // append sequences is not required across GOPs (just within GOPs).
1843 AddTestTracks(HAS_VIDEO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1844 frame_processor_->SetSequenceMode(use_sequence_mode_);
1846 // Make the sequence mode buffering appear just like segments mode to simplify
1848 if (use_sequence_mode_)
1849 SetTimestampOffset(Milliseconds(200));
1853 OnGroupStart(DemuxerStream::VIDEO,
1854 DecodeTimestamp::FromPresentationTime(Milliseconds(200)),
1855 Milliseconds(200)));
1856 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1857 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(240)));
1858 EXPECT_TRUE(ProcessFrames("", "200K 210 220 230"));
1859 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1860 CheckExpectedRangesByTimestamp(video_.get(), "{ [200,240) }");
1864 OnGroupStart(DemuxerStream::VIDEO,
1865 DecodeTimestamp::FromPresentationTime(Milliseconds(225)),
1866 Milliseconds(240)));
1867 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::VIDEO, _));
1868 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(280)));
1869 // Append a second GOP whose first DTS is below the last DTS of the first GOP,
1870 // but whose PTS interval is continuous with the end of the first GOP.
1871 EXPECT_TRUE(ProcessFrames("", "240|225K 250|235 260|245 270|255"));
1872 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1873 SeekStream(video_.get(), Milliseconds(200));
1875 CheckExpectedRangesByTimestamp(video_.get(), "{ [200,280) }");
1876 CheckReadsThenReadStalls(video_.get(), "200 210 220 230 240 250 260 270");
1879 TEST_P(FrameProcessorTest, OnlyKeyframes_ContinuousDts_ContinousPts_1) {
1880 // Verifies that precisely one group start and one stream append occurs for a
1881 // single continuous set of frames.
1883 AddTestTracks(HAS_AUDIO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1884 if (use_sequence_mode_)
1885 frame_processor_->SetSequenceMode(true);
1887 // Default test frame duration is 10 milliseconds.
1889 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::AUDIO, DecodeTimestamp(),
1890 base::TimeDelta()));
1891 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1892 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(40)));
1893 EXPECT_TRUE(ProcessFrames("0K 10K 20K 30K", ""));
1894 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1896 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
1897 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
1900 TEST_P(FrameProcessorTest, OnlyKeyframes_ContinuousDts_ContinuousPts_2) {
1901 // Verifies that precisely one group start and one stream append occurs while
1902 // processing a single continuous set of frames that uses fudge room to just
1903 // barely remain adjacent.
1905 AddTestTracks(HAS_AUDIO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1906 if (use_sequence_mode_)
1907 frame_processor_->SetSequenceMode(true);
1909 frame_duration_ = Milliseconds(5);
1911 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::AUDIO, DecodeTimestamp(),
1912 base::TimeDelta()));
1913 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1914 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(35)));
1915 EXPECT_TRUE(ProcessFrames("0K 10K 20K 30K", ""));
1916 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1918 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,35) }");
1919 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
1922 TEST_P(FrameProcessorTest,
1923 OnlyKeyframes_ContinuousDts_DiscontinuousPtsJustBeyondFudgeRoom) {
1924 // Verifies that multiple group starts and distinct appends occur
1925 // when processing a single DTS-continuous set of frames with PTS deltas that
1926 // just barely exceed the adjacency assumption in FrameProcessor.
1928 AddTestTracks(HAS_AUDIO | OBSERVE_APPENDS_AND_GROUP_STARTS);
1929 if (use_sequence_mode_)
1930 frame_processor_->SetSequenceMode(true);
1932 frame_duration_ = base::Microseconds(4999);
1934 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::AUDIO, DecodeTimestamp(),
1935 base::TimeDelta()));
1936 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1937 // Frame "10|5K" following "0K" triggers start of new group and eventual
1939 EXPECT_CALL(callbacks_, OnGroupStart(DemuxerStream::AUDIO, DecodeTimestamp(),
1941 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1943 // Frame "20|10K" following "10|5K" triggers start of new group and eventual
1947 OnGroupStart(DemuxerStream::AUDIO,
1948 DecodeTimestamp::FromPresentationTime(Milliseconds(5)),
1949 Milliseconds(10) + frame_duration_));
1950 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1952 // Frame "30|15K" following "20|10K" triggers start of new group and
1956 OnGroupStart(DemuxerStream::AUDIO,
1957 DecodeTimestamp::FromPresentationTime(Milliseconds(10)),
1958 Milliseconds(20) + frame_duration_));
1959 EXPECT_CALL(callbacks_, OnAppend(DemuxerStream::AUDIO, _));
1961 EXPECT_CALL(callbacks_, PossibleDurationIncrease(base::Microseconds(34999)));
1962 EXPECT_TRUE(ProcessFrames("0K 10|5K 20|10K 30|15K", ""));
1963 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
1965 // Note that the result is still buffered continuous since DTS was continuous
1966 // and PTS was monotonically increasing (such that each group start was
1967 // signalled by FrameProcessor to be continuous with the end of the previous
1969 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,34) }");
1970 CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
1973 TEST_P(FrameProcessorTest,
1974 GroupEndTimestampDecreaseWithinMediaSegmentShouldWarn) {
1975 // This parse warning requires:
1976 // 1) a decode time discontinuity within the set of frames being processed,
1977 // 2) the highest frame end time of any frame successfully processed
1978 // before that discontinuity is higher than the highest frame end time of
1979 // all frames processed after that discontinuity.
1980 // TODO(wolenetz): Adjust this case once direction on spec is informed by
1981 // data. See https://crbug.com/920853 and
1982 // https://github.com/w3c/media-source/issues/203.
1983 if (use_sequence_mode_) {
1984 // Sequence mode modifies the presentation timestamps following a decode
1985 // discontinuity such that this scenario should not repro with that mode.
1986 DVLOG(1) << "Skipping segments mode variant; inapplicable to this case.";
1991 AddTestTracks(HAS_VIDEO);
1993 EXPECT_CALL(callbacks_,
1994 OnParseWarning(SourceBufferParseWarning::
1995 kGroupEndTimestampDecreaseWithinMediaSegment));
1997 frame_duration_ = Milliseconds(10);
1998 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(15)));
1999 EXPECT_TRUE(ProcessFrames("", "0K 10K 5|40K"));
2000 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2002 CheckExpectedRangesByTimestamp(video_.get(), "{ [0,15) }");
2003 CheckReadsThenReadStalls(video_.get(), "0 5");
2006 TEST_P(FrameProcessorTest, NonkeyframeAudioBuffering_BasicOperation) {
2007 // With the support for audio nonkeyframe buffering enabled, buffer a couple
2008 // continuous groups of audio key and nonkey frames.
2009 // Note, see the AudioNonKeyframeChangedToKeyframe test that tests where
2010 // nonkeyframe audio buffering is not supported, and instead takes a
2011 // workaround that forces all audio to be keyframe.
2013 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2014 if (use_sequence_mode_)
2015 frame_processor_->SetSequenceMode(true);
2017 // Default test frame duration is 10 milliseconds.
2018 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(80)));
2019 EXPECT_TRUE(ProcessFrames("0K 10 20 30 40K 50 60 70", ""));
2020 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2022 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,80) }");
2023 CheckReadsAndKeyframenessThenReadStalls(audio_.get(),
2024 "0K 10N 20N 30N 40K 50N 60N 70N");
2027 TEST_P(FrameProcessorTest, NonkeyframeAudioBuffering_BasicOverlaps) {
2028 // With the support for audio nonkeyframe buffering enabled, buffer a few
2029 // groups of audio key and nonkey frames which overlap each other.
2030 // For sequence mode versions, timestampOffset is adjusted to make it act like
2033 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2034 if (use_sequence_mode_) {
2035 frame_processor_->SetSequenceMode(true);
2036 SetTimestampOffset(Milliseconds(10));
2039 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
2040 EXPECT_TRUE(ProcessFrames("10K 20 30 40 50", ""));
2041 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2042 CheckExpectedRangesByTimestamp(audio_.get(), "{ [10,60) }");
2044 // End-overlap the last nonkeyframe appended with a keyframe.
2046 if (use_sequence_mode_)
2047 SetTimestampOffset(Milliseconds(50));
2049 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(70)));
2050 EXPECT_TRUE(ProcessFrames("50K 60", ""));
2051 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2052 CheckExpectedRangesByTimestamp(audio_.get(), "{ [10,70) }");
2054 // Front-overlap the original group of frames.
2056 if (use_sequence_mode_)
2057 SetTimestampOffset(Milliseconds(0));
2059 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
2060 EXPECT_TRUE(ProcessFrames("0K 10", ""));
2061 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2062 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,70) }");
2064 SeekStream(audio_.get(), Milliseconds(0));
2065 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "0K 10N 50K 60N");
2068 TEST_P(FrameProcessorTest,
2069 NonkeyframeAudioBuffering_InitialNonkeyframesNotBuffered) {
2070 // With the support for audio nonkeyframe buffering enabled, try to buffer
2071 // some frames beginning with a nonkeyframe and observe initial nonkeyframe(s)
2072 // are not buffered.
2074 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2075 if (use_sequence_mode_)
2076 frame_processor_->SetSequenceMode(true);
2078 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(60)));
2079 EXPECT_TRUE(ProcessFrames("0 10 20K 30 40 50", ""));
2080 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2081 CheckExpectedRangesByTimestamp(audio_.get(), "{ [20,60) }");
2082 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "20K 30N 40N 50N");
2085 TEST_P(FrameProcessorTest,
2086 NonkeyframeAudioBuffering_InvalidDecreasingNonkeyframePts) {
2087 // With the support for audio nonkeyframe buffering enabled, try to buffer an
2088 // invalid sequence of nonkeyframes: decreasing presentation timestamps are
2089 // not supported for audio nonkeyframes. For sequence mode versions,
2090 // timestampOffset is adjusted to make it act like segments mode.
2092 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2093 if (use_sequence_mode_) {
2094 frame_processor_->SetSequenceMode(true);
2095 SetTimestampOffset(Milliseconds(100));
2098 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(110)));
2099 EXPECT_TRUE(ProcessFrames("100K", ""));
2100 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2101 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,110) }");
2103 // Processing an audio nonkeyframe with lower PTS than the previous frame
2105 EXPECT_MEDIA_LOG(AudioNonKeyframeOutOfOrder());
2106 EXPECT_FALSE(ProcessFrames("90|110", ""));
2109 TEST_P(FrameProcessorTest,
2110 NonkeyframeAudioBuffering_ValidDecreasingKeyframePts) {
2111 // With the support for audio nonkeyframe buffering enabled, try to buffer a
2112 // valid sequence of key and nonkeyframes: decreasing presentation timestamps
2113 // are supported for keyframes. For sequence mode versions, timestampOffset is
2114 // adjusted to make it act like segments mode.
2116 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2117 if (use_sequence_mode_) {
2118 frame_processor_->SetSequenceMode(true);
2119 SetTimestampOffset(Milliseconds(100));
2122 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(130)));
2123 EXPECT_TRUE(ProcessFrames("100K 110 120", ""));
2124 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2125 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,130) }");
2127 // Processing an audio keyframe with lower PTS than the previous frame
2128 // should succeed, since it is a keyframe. Here, we use continuous DTS to
2129 // ensure we precisely target the nonkeyframe monotonicity check when a
2130 // keyframe is not required by the track buffer currently (and to make
2131 // sequence mode versions act like segments mode without further manual
2132 // adjustment of timestamp offset.) The original nonkeyframe at PTS 110 should
2133 // be overlap-removed, and the one at PTS 120 should have be removed as a
2134 // result of depending on that removed PTS 110 nonkeyframe.
2135 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(130)));
2136 EXPECT_TRUE(ProcessFrames("110|130K", ""));
2137 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2138 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,120) }");
2139 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "100K 110K");
2142 TEST_P(FrameProcessorTest,
2143 NonkeyframeAudioBuffering_ValidSameNonKeyframePts_1) {
2144 // With the support for audio nonkeyframe buffering enabled, try to buffer a
2145 // valid sequence of a keyframe and a nonkeyframe: non-increasing presentation
2146 // timestamps are supported for audio nonkeyframes, so long as they don't
2147 // decrease. For sequence mode versions, timestampOffset is adjusted to make
2148 // it act like segments mode.
2150 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2151 if (use_sequence_mode_) {
2152 frame_processor_->SetSequenceMode(true);
2153 SetTimestampOffset(Milliseconds(100));
2156 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(110)));
2157 EXPECT_TRUE(ProcessFrames("100K", ""));
2158 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2159 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,110) }");
2161 // Processing an audio nonkeyframe with same PTS as the previous frame should
2162 // succeed, though there is presentation interval overlap causing removal of
2163 // the previous frame (in this case, a keyframe), and hence the new dependent
2164 // nonkeyframe is not buffered.
2165 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(110)));
2166 EXPECT_TRUE(ProcessFrames("100|110", ""));
2167 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2168 CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
2169 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "");
2172 TEST_P(FrameProcessorTest,
2173 NonkeyframeAudioBuffering_ValidSameNonKeyframePts_2) {
2174 // With the support for audio nonkeyframe buffering enabled, try to buffer a
2175 // valid sequence of nonkeyframes: non-increasing presentation timestamps are
2176 // supported for audio nonkeyframes, so long as they don't decrease. For
2177 // sequence mode versions, timestampOffset is adjusted to make it act like
2180 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2181 if (use_sequence_mode_) {
2182 frame_processor_->SetSequenceMode(true);
2183 SetTimestampOffset(Milliseconds(100));
2186 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(120)));
2187 EXPECT_TRUE(ProcessFrames("100K 110", ""));
2188 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2189 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,120) }");
2191 // Processing an audio nonkeyframe with same PTS as the previous frame should
2192 // succeed, though there is presentation interval overlap causing removal of
2193 // the previous nonkeyframe, and hence the new dependent nonkeyframe is not
2195 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(120)));
2196 EXPECT_TRUE(ProcessFrames("110|120", ""));
2197 EXPECT_EQ(Milliseconds(0), timestamp_offset_);
2198 CheckExpectedRangesByTimestamp(audio_.get(), "{ [100,110) }");
2199 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "100K");
2202 TEST_P(FrameProcessorTest,
2203 NonkeyframeAudioBuffering_AppendWindowFilterDroppedPrerollKeyframe) {
2204 // For simplicity currently, if the preroll (keyframe) buffer was entirely
2205 // prior to the append window and dropped, an approximately continuous
2206 // keyframe is still required to use that dropped frame as preroll (for
2207 // simplicity). This may change in future if append window trimming of
2208 // nonkeyframes with a fully excluded preroll keyframe is commonly needed to
2211 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2212 if (use_sequence_mode_)
2213 frame_processor_->SetSequenceMode(true);
2214 SetTimestampOffset(Milliseconds(-10));
2216 EXPECT_MEDIA_LOG(DroppedFrame("audio", -10000));
2217 if (use_sequence_mode_)
2218 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(-10)));
2220 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(0)));
2221 EXPECT_TRUE(ProcessFrames("0K", ""));
2223 // This nonkeyframe is dropped for simplicity since it depends on a preroll
2224 // keyframe which was entirely outside the append window.
2225 if (use_sequence_mode_)
2226 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(-10)));
2228 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(0)));
2229 EXPECT_TRUE(ProcessFrames("10", ""));
2231 // Only the following keyframe should buffer successfully, with no preroll.
2232 EXPECT_MEDIA_LOG(DroppedAppendWindowUnusedPreroll(-10000, -10000, 10000));
2233 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(20)));
2234 EXPECT_TRUE(ProcessFrames("20K", ""));
2236 CheckExpectedRangesByTimestamp(audio_.get(), "{ [10,20) }");
2237 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "10:20K");
2240 TEST_P(FrameProcessorTest,
2241 NonkeyframeAudioBuffering_AppendWindowFilter_TrimFront) {
2243 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2244 if (use_sequence_mode_)
2245 frame_processor_->SetSequenceMode(true);
2246 SetTimestampOffset(Milliseconds(-4));
2247 EXPECT_MEDIA_LOG(TruncatedFrame(-4000, 6000, "start", 0));
2248 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(26)));
2249 EXPECT_TRUE(ProcessFrames("0K 10 20", ""));
2250 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,26) }");
2251 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "0K 6:10N 16:20N");
2254 TEST_P(FrameProcessorTest,
2255 NonkeyframeAudioBuffering_AppendWindowFilter_TrimEnd) {
2257 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2258 if (use_sequence_mode_)
2259 frame_processor_->SetSequenceMode(true);
2261 append_window_end_ = Milliseconds(26);
2263 EXPECT_MEDIA_LOG(TruncatedFrame(20000, 30000, "end", 26000));
2264 EXPECT_MEDIA_LOG(DroppedFrameCheckAppendWindow("audio", 0, 26000));
2265 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(26)));
2266 EXPECT_TRUE(ProcessFrames("0K 10 20 30", ""));
2267 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,26) }");
2268 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "0K 10N 20N");
2271 TEST_P(FrameProcessorTest, NonkeyframeAudioBuffering_TrimSpliceOverlap) {
2272 // White-box test which focuses on the behavior of underlying
2273 // SourceBufferStream::TrimSpliceOverlap() for frame sequences involving
2274 // nonkeyframes appended by the FrameProcessor. That method detects and
2275 // performs splice trimming on every audio frame following either a
2276 // discontinuity or the beginning of ProcessFrames(), and also on audio frames
2277 // with PTS not directly continuous with the highest frame end PTS already
2278 // processed. We vary |frame_duration_| in this test to avoid confusing
2279 // int:decimal pairs in the eventual CheckReads* call.
2281 AddTestTracks(HAS_AUDIO | USE_AUDIO_CODEC_SUPPORTING_NONKEYFRAMES);
2282 if (use_sequence_mode_)
2283 frame_processor_->SetSequenceMode(true);
2285 frame_duration_ = base::Microseconds(9750);
2286 EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
2287 EXPECT_TRUE(ProcessFrames("0K", ""));
2289 // As with all-keyframe streams, a slight jump forward should not trigger any
2290 // splicing logic, though accumulations of these may result in loss of A/V
2292 frame_duration_ = base::Microseconds(10250);
2293 EXPECT_CALL(callbacks_,
2294 PossibleDurationIncrease(Milliseconds(10) + frame_duration_));
2295 EXPECT_TRUE(ProcessFrames("10", ""));
2297 // As with all-keyframe streams, a slightly end-overlapping nonkeyframe should
2298 // not trigger any splicing logic, though accumulations of these may result in
2299 // loss of A/V sync. The difference here is there isn't even any emission of a
2300 // "too little splice overlap" media log, since the new frame is a
2302 frame_duration_ = Milliseconds(10);
2303 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(30)));
2304 EXPECT_TRUE(ProcessFrames("20", ""));
2306 // A heavily overlapping nonkeyframe should not trigger any splicing logic,
2307 // so long as it isn't completely discontinuous. This is unlike all-keyframe
2308 // audio streams, where such a heavy overlap would end-trim the overlapped
2309 // frame. Accumulations of these could rapidly lead to loss of A/V sync.
2310 // Nonkeyframe timestamp & duration metadata sequences need to be correctly
2311 // muxed to avoid this.
2312 frame_duration_ = base::Microseconds(10250);
2313 EXPECT_CALL(callbacks_,
2314 PossibleDurationIncrease(Milliseconds(22) + frame_duration_));
2315 EXPECT_TRUE(ProcessFrames("22", ""));
2317 // A keyframe that end-overlaps a nonkeyframe will trigger splicing logic.
2318 // Here, we test a "too little splice overlap" case.
2319 frame_duration_ = Milliseconds(10);
2320 EXPECT_MEDIA_LOG(SkippingSpliceTooLittleOverlap(32000, 250));
2321 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(42)));
2322 EXPECT_TRUE(ProcessFrames("32K", ""));
2324 // And a keyframe that significantly end-overlaps a nonkeyframe will trigger
2325 // splicing logic that can perform end-trimming of the overlapped frame.
2326 // First, we buffer another nonkeyframe.
2327 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(52)));
2328 EXPECT_TRUE(ProcessFrames("42", ""));
2329 // Verify correct splice behavior on significant overlap of the nonkeyframe by
2331 EXPECT_MEDIA_LOG(TrimmedSpliceOverlap(45000, 42000, 7000));
2332 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(55)));
2333 EXPECT_TRUE(ProcessFrames("45K", ""));
2335 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,55) }");
2336 CheckReadsAndKeyframenessThenReadStalls(audio_.get(),
2337 "0K 10N 20N 22N 32K 42N 45K");
2340 TEST_P(FrameProcessorTest, FrameDuration_kNoTimestamp_Fails) {
2342 AddTestTracks(HAS_AUDIO);
2343 frame_processor_->SetSequenceMode(use_sequence_mode_);
2345 frame_duration_ = kNoTimestamp;
2346 EXPECT_MEDIA_LOG(FrameDurationUnknown("audio", 1000));
2347 EXPECT_FALSE(ProcessFrames("1K", ""));
2350 TEST_P(FrameProcessorTest,
2351 Pts_BeforeTimestampOffsetApplied_kNoTimestamp_Fails) {
2353 AddTestTracks(HAS_AUDIO);
2354 frame_processor_->SetSequenceMode(use_sequence_mode_);
2356 EXPECT_MEDIA_LOG(PtsUnknown("audio"));
2357 EXPECT_FALSE(ProcessFrames("MinK", ""));
2360 TEST_P(FrameProcessorTest,
2361 Pts_BeforeTimestampOffsetApplied_kInfiniteDuration_Fails) {
2363 AddTestTracks(HAS_AUDIO);
2364 frame_processor_->SetSequenceMode(use_sequence_mode_);
2366 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("Before adjusting by timestampOffset",
2368 EXPECT_FALSE(ProcessFrames("MaxK", ""));
2371 TEST_P(FrameProcessorTest,
2372 Dts_BeforeTimestampOffsetApplied_kNoDecodeTimestamp_UsesPtsIfValid) {
2374 AddTestTracks(HAS_AUDIO);
2375 frame_processor_->SetSequenceMode(use_sequence_mode_);
2377 // When PTS is valid, but DTS is kNoDecodeTimestamp, then
2378 // StreamParserBuffer::GetDecodeTimestamp() just returns the frame's PTS.
2379 EXPECT_CALL(callbacks_, PossibleDurationIncrease(Milliseconds(10)));
2380 EXPECT_TRUE(ProcessFrames("0|MinK", ""));
2382 CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) }");
2383 CheckReadsAndKeyframenessThenReadStalls(audio_.get(), "0K");
2386 TEST_P(FrameProcessorTest,
2387 Dts_BeforeTimestampOffsetApplied_kMaxDecodeTimestamp_Fails) {
2389 AddTestTracks(HAS_AUDIO);
2390 frame_processor_->SetSequenceMode(use_sequence_mode_);
2392 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("Before adjusting by timestampOffset",
2394 EXPECT_FALSE(ProcessFrames("0|MaxK", ""));
2397 TEST_P(FrameProcessorTest, After_Sequence_OffsetUpdate_kNoTimestamp_Fails) {
2398 if (!use_sequence_mode_) {
2399 DVLOG(1) << "Skipping segments mode variant; inapplicable to this case.";
2404 AddTestTracks(HAS_AUDIO);
2405 frame_processor_->SetSequenceMode(use_sequence_mode_);
2407 // (-Infinity + 5)ms minus 10ms saturates to (-Infinity)ms.
2408 SetTimestampOffset(kNoTimestamp + Milliseconds(5));
2409 EXPECT_MEDIA_LOG(SequenceOffsetUpdateOutOfRange());
2410 EXPECT_FALSE(ProcessFrames("10K", ""));
2413 TEST_P(FrameProcessorTest,
2414 After_Sequence_OffsetUpdate_kInfiniteDuration_Fails) {
2415 if (!use_sequence_mode_) {
2416 DVLOG(1) << "Skipping segments mode variant; inapplicable to this case.";
2421 AddTestTracks(HAS_AUDIO);
2422 frame_processor_->SetSequenceMode(use_sequence_mode_);
2424 // (+Infinity - 5)ms minus -10ms saturates to (+Infinity)ms.
2425 SetTimestampOffset(kInfiniteDuration - Milliseconds(5));
2426 EXPECT_MEDIA_LOG(SequenceOffsetUpdateOutOfRange());
2427 EXPECT_FALSE(ProcessFrames("-10K", ""));
2430 TEST_P(FrameProcessorTest,
2431 Before_Sequence_OffsetUpdate_kInfiniteDuration_Fails) {
2432 if (!use_sequence_mode_) {
2433 DVLOG(1) << "Skipping segments mode variant; inapplicable to this case.";
2438 AddTestTracks(HAS_AUDIO);
2439 frame_processor_->SetSequenceMode(use_sequence_mode_);
2441 // Effectively sets group start timestamp to +Infinity.
2442 SetTimestampOffset(kInfiniteDuration);
2444 SequenceOffsetUpdatePreventedByOutOfRangeGroupStartTimestamp());
2446 // That infinite value fails precondition of finite value for group start
2447 // timestamp when about to update timestampOffset based upon it.
2448 EXPECT_FALSE(ProcessFrames("0K", ""));
2451 TEST_P(FrameProcessorTest, Segments_InfiniteTimestampOffset_Fails) {
2452 if (use_sequence_mode_) {
2453 DVLOG(1) << "Skipping sequence mode variant; inapplicable to this case.";
2458 AddTestTracks(HAS_AUDIO);
2459 frame_processor_->SetSequenceMode(use_sequence_mode_);
2461 SetTimestampOffset(kInfiniteDuration);
2462 EXPECT_MEDIA_LOG(OffsetOutOfRange());
2463 EXPECT_FALSE(ProcessFrames("0K", ""));
2466 TEST_P(FrameProcessorTest, Pts_AfterTimestampOffsetApplied_kNoTimestamp_Fails) {
2468 AddTestTracks(HAS_VIDEO);
2469 frame_processor_->SetSequenceMode(use_sequence_mode_);
2471 // Note, SetTimestampOffset(kNoTimestamp) hits DCHECK. This test instead
2472 // checks that the result of offset application to PTS gives parse error if
2473 // the result is <= kNoTimestamp. Getting such a result requires different
2474 // test logic for segments vs sequence append modes.
2475 if (use_sequence_mode_) {
2476 // Use an extremely out-of-order DTS/PTS GOP to get the resulting
2477 // timestampOffset needed for application to a nonkeyframe PTS (continuous
2478 // in DTS time with its GOP's keyframe), resulting with kNoTimestamp PTS.
2479 // First, calculate (-kNoTimestamp - 10ms), truncated down to nearest
2480 // millisecond, for use as keyframe PTS and DTS.
2481 frame_duration_ = Milliseconds(1);
2482 base::TimeDelta ts =
2483 Milliseconds(((kNoTimestamp + Milliseconds(10)) * -1).InMilliseconds());
2484 std::string ts_str = base::NumberToString(ts.InMilliseconds());
2486 // Append the keyframe and expect success for this step.
2487 EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
2488 EXPECT_TRUE(ProcessFrames("", ts_str + "|" + ts_str + "K"));
2489 EXPECT_EQ(timestamp_offset_.InMicroseconds(), (-1 * ts).InMicroseconds());
2491 // A nonkeyframe with the same DTS as previous frame does not cause any
2492 // discontinuity. Append such a frame, with PTS before offset applied that
2493 // saturates to kNoTimestamp when the offset is applied.
2494 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("After adjusting by timestampOffset",
2496 EXPECT_FALSE(ProcessFrames("", "-20|" + ts_str));
2498 // Set the offset to be just above kNoTimestamp, and append a frame with a
2499 // PTS that is negative by at least that small amount. The result should
2500 // saturate to kNoTimestamp for PTS.
2501 SetTimestampOffset(kNoTimestamp + Milliseconds(1));
2502 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("After adjusting by timestampOffset",
2504 EXPECT_FALSE(ProcessFrames("", "-2K"));
2508 TEST_P(FrameProcessorTest,
2509 Pts_AfterTimestampOffsetApplied_kInfiniteDuration_Fails) {
2512 AddTestTracks(HAS_VIDEO);
2513 frame_processor_->SetSequenceMode(use_sequence_mode_);
2515 // Use a video GOP with a nonkeyframe PTS that jumps forward far enough to
2516 // saturate to kInfiniteDuration after timestampOffset is applied. Take care
2517 // to avoid saturating the (earlier) keyframe's frame_end_timestamp to
2518 // kInfiniteDuration, avoiding a different parse error case.
2519 // First, calculate (kInfiniteDuration - 2ms), truncated down to nearest
2520 // millisecond for use as keyframe PTS (after timestamp offset application).
2521 // It's also used for start of DTS sequence.
2522 frame_duration_ = Milliseconds(1);
2523 base::TimeDelta ts =
2524 Milliseconds((kInfiniteDuration - Milliseconds(2)).InMilliseconds());
2526 // Append the keyframe and expect success for this step.
2527 SetTimestampOffset(ts);
2528 EXPECT_CALL(callbacks_, PossibleDurationIncrease(ts + frame_duration_));
2529 EXPECT_TRUE(ProcessFrames("", "0K"));
2531 // Sequence mode might adjust the offset. This test's logic should ensure the
2532 // offset is the same as in segments mode at this point.
2533 EXPECT_EQ(timestamp_offset_.InMicroseconds(), ts.InMicroseconds());
2535 // A nonkeyframe with same DTS as previous frame does not cause any
2536 // discontinuity. Append such a frame, with PTS jumped 3ms forwards such that
2537 // it saturates to kInfiniteDuration when offset is applied.
2538 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("After adjusting by timestampOffset",
2540 EXPECT_FALSE(ProcessFrames("", "3|0"));
2543 TEST_P(FrameProcessorTest,
2544 Dts_AfterTimestampOffsetApplied_kNoDecodeTimestamp_Fails) {
2547 AddTestTracks(HAS_AUDIO);
2548 frame_processor_->SetSequenceMode(use_sequence_mode_);
2550 SetTimestampOffset(kNoTimestamp + Milliseconds(5));
2551 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("After adjusting by timestampOffset",
2553 EXPECT_FALSE(ProcessFrames("0|-10K", ""));
2556 TEST_P(FrameProcessorTest,
2557 Dts_AfterTimestampOffsetApplied_kMaxDecodeTimestamp_Fails) {
2560 AddTestTracks(HAS_AUDIO);
2561 frame_processor_->SetSequenceMode(use_sequence_mode_);
2563 SetTimestampOffset(kInfiniteDuration - Milliseconds(5));
2564 EXPECT_MEDIA_LOG(FrameTimeOutOfRange("After adjusting by timestampOffset",
2566 EXPECT_FALSE(ProcessFrames("0|10K", ""));
2569 TEST_P(FrameProcessorTest, FrameEndTimestamp_kInfiniteDuration_Fails) {
2572 AddTestTracks(HAS_AUDIO);
2573 frame_processor_->SetSequenceMode(use_sequence_mode_);
2575 frame_duration_ = Milliseconds(10);
2576 SetTimestampOffset(kInfiniteDuration - Milliseconds(5));
2577 EXPECT_MEDIA_LOG(FrameEndTimestampOutOfRange("audio"));
2578 EXPECT_FALSE(ProcessFrames("0|0K", ""));
2581 INSTANTIATE_TEST_SUITE_P(SequenceMode, FrameProcessorTest, Values(true));
2582 INSTANTIATE_TEST_SUITE_P(SegmentsMode, FrameProcessorTest, Values(false));
2584 } // namespace media