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