Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / media / filters / frame_processor_unittest.cc
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 <map>
6 #include <string>
7
8 #include "base/bind.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "base/time/time.h"
14 #include "media/base/mock_filters.h"
15 #include "media/base/test_helpers.h"
16 #include "media/filters/chunk_demuxer.h"
17 #include "media/filters/frame_processor.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 using ::testing::InSequence;
21 using ::testing::StrictMock;
22 using ::testing::Values;
23
24 namespace media {
25
26 typedef StreamParser::BufferQueue BufferQueue;
27 typedef StreamParser::TextBufferQueueMap TextBufferQueueMap;
28 typedef StreamParser::TrackId TrackId;
29
30 static void LogFunc(const std::string& str) { DVLOG(1) << str; }
31
32 // Used for setting expectations on callbacks. Using a StrictMock also lets us
33 // test for missing or extra callbacks.
34 class FrameProcessorTestCallbackHelper {
35  public:
36   FrameProcessorTestCallbackHelper() {}
37   virtual ~FrameProcessorTestCallbackHelper() {}
38
39   MOCK_METHOD1(PossibleDurationIncrease, void(base::TimeDelta new_duration));
40
41   // Helper that calls the mock method as well as does basic sanity checks on
42   // |new_duration|.
43   void OnPossibleDurationIncrease(base::TimeDelta new_duration) {
44     PossibleDurationIncrease(new_duration);
45     ASSERT_NE(kNoTimestamp(), new_duration);
46     ASSERT_NE(kInfiniteDuration(), new_duration);
47   }
48
49  private:
50   DISALLOW_COPY_AND_ASSIGN(FrameProcessorTestCallbackHelper);
51 };
52
53 // Test parameter determines indicates if the TEST_P instance is targeted for
54 // sequence mode (if true), or segments mode (if false).
55 class FrameProcessorTest : public testing::TestWithParam<bool> {
56  protected:
57   FrameProcessorTest()
58       : frame_processor_(new FrameProcessor(base::Bind(
59             &FrameProcessorTestCallbackHelper::OnPossibleDurationIncrease,
60             base::Unretained(&callbacks_)))),
61         append_window_end_(kInfiniteDuration()),
62         new_media_segment_(false),
63         audio_id_(FrameProcessor::kAudioTrackId),
64         video_id_(FrameProcessor::kVideoTrackId),
65         frame_duration_(base::TimeDelta::FromMilliseconds(10)) {
66   }
67
68   enum StreamFlags {
69     HAS_AUDIO = 1 << 0,
70     HAS_VIDEO = 1 << 1
71   };
72
73   void AddTestTracks(int stream_flags) {
74     const bool has_audio = (stream_flags & HAS_AUDIO) != 0;
75     const bool has_video = (stream_flags & HAS_VIDEO) != 0;
76     ASSERT_TRUE(has_audio || has_video);
77
78     if (has_audio) {
79       CreateAndConfigureStream(DemuxerStream::AUDIO);
80       ASSERT_TRUE(audio_);
81       EXPECT_TRUE(frame_processor_->AddTrack(audio_id_, audio_.get()));
82       audio_->Seek(base::TimeDelta());
83       audio_->StartReturningData();
84     }
85     if (has_video) {
86       CreateAndConfigureStream(DemuxerStream::VIDEO);
87       ASSERT_TRUE(video_);
88       EXPECT_TRUE(frame_processor_->AddTrack(video_id_, video_.get()));
89       video_->Seek(base::TimeDelta());
90       video_->StartReturningData();
91     }
92   }
93
94   void SetTimestampOffset(base::TimeDelta new_offset) {
95     timestamp_offset_ = new_offset;
96     frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset_);
97   }
98
99   BufferQueue StringToBufferQueue(const std::string& buffers_to_append,
100                                   const TrackId track_id,
101                                   const DemuxerStream::Type type) {
102     std::vector<std::string> timestamps;
103     base::SplitString(buffers_to_append, ' ', &timestamps);
104
105     BufferQueue buffers;
106     for (size_t i = 0; i < timestamps.size(); i++) {
107       bool is_keyframe = false;
108       if (EndsWith(timestamps[i], "K", true)) {
109         is_keyframe = true;
110         // Remove the "K" off of the token.
111         timestamps[i] = timestamps[i].substr(0, timestamps[i].length() - 1);
112       }
113
114       double time_in_ms;
115       CHECK(base::StringToDouble(timestamps[i], &time_in_ms));
116
117       // Create buffer. Encode the original time_in_ms as the buffer's data to
118       // enable later verification of possible buffer relocation in presentation
119       // timeline due to coded frame processing.
120       const uint8* timestamp_as_data = reinterpret_cast<uint8*>(&time_in_ms);
121       scoped_refptr<StreamParserBuffer> buffer =
122           StreamParserBuffer::CopyFrom(timestamp_as_data, sizeof(time_in_ms),
123                                        is_keyframe, type, track_id);
124       base::TimeDelta timestamp = base::TimeDelta::FromSecondsD(
125           time_in_ms / base::Time::kMillisecondsPerSecond);
126       buffer->set_timestamp(timestamp);
127       buffer->set_duration(frame_duration_);
128       buffers.push_back(buffer);
129     }
130     return buffers;
131   }
132
133   void ProcessFrames(const std::string& audio_timestamps,
134                      const std::string& video_timestamps) {
135     ASSERT_TRUE(frame_processor_->ProcessFrames(
136         StringToBufferQueue(audio_timestamps, audio_id_, DemuxerStream::AUDIO),
137         StringToBufferQueue(video_timestamps, video_id_, DemuxerStream::VIDEO),
138         empty_text_buffers_,
139         append_window_start_, append_window_end_,
140         &new_media_segment_, &timestamp_offset_));
141   }
142
143   void CheckExpectedRangesByTimestamp(ChunkDemuxerStream* stream,
144                                       const std::string& expected) {
145     // Note, DemuxerStream::TEXT streams return [0,duration (==infinity here))
146     Ranges<base::TimeDelta> r = stream->GetBufferedRanges(kInfiniteDuration());
147
148     std::stringstream ss;
149     ss << "{ ";
150     for (size_t i = 0; i < r.size(); ++i) {
151       int64 start = r.start(i).InMilliseconds();
152       int64 end = r.end(i).InMilliseconds();
153       ss << "[" << start << "," << end << ") ";
154     }
155     ss << "}";
156     EXPECT_EQ(expected, ss.str());
157   }
158
159   void CheckReadStalls(ChunkDemuxerStream* stream) {
160     int loop_count = 0;
161
162     do {
163       read_callback_called_ = false;
164       stream->Read(base::Bind(&FrameProcessorTest::StoreStatusAndBuffer,
165                               base::Unretained(this)));
166       message_loop_.RunUntilIdle();
167     } while (++loop_count < 2 && read_callback_called_ &&
168              last_read_status_ == DemuxerStream::kAborted);
169
170     ASSERT_FALSE(read_callback_called_ &&
171                  last_read_status_ == DemuxerStream::kAborted)
172         << "2 kAborted reads in a row. Giving up.";
173     EXPECT_FALSE(read_callback_called_);
174   }
175
176   // Format of |expected| is a space-delimited sequence of
177   // timestamp_in_ms:original_timestamp_in_ms
178   // original_timestamp_in_ms (and the colon) must be omitted if it is the same
179   // as timestamp_in_ms.
180   void CheckReadsThenReadStalls(ChunkDemuxerStream* stream,
181                                 const std::string& expected) {
182     std::vector<std::string> timestamps;
183     base::SplitString(expected, ' ', &timestamps);
184     std::stringstream ss;
185     for (size_t i = 0; i < timestamps.size(); ++i) {
186       int loop_count = 0;
187
188       do {
189         read_callback_called_ = false;
190         stream->Read(base::Bind(&FrameProcessorTest::StoreStatusAndBuffer,
191                                 base::Unretained(this)));
192         message_loop_.RunUntilIdle();
193         EXPECT_TRUE(read_callback_called_);
194       } while (++loop_count < 2 &&
195                last_read_status_ == DemuxerStream::kAborted);
196
197       ASSERT_FALSE(last_read_status_ == DemuxerStream::kAborted)
198           << "2 kAborted reads in a row. Giving up.";
199       EXPECT_EQ(DemuxerStream::kOk, last_read_status_);
200       EXPECT_FALSE(last_read_buffer_->end_of_stream());
201
202       if (i > 0)
203         ss << " ";
204
205       int time_in_ms = last_read_buffer_->timestamp().InMilliseconds();
206       ss << time_in_ms;
207
208       // Decode the original_time_in_ms from the buffer's data.
209       double original_time_in_ms;
210       ASSERT_EQ(static_cast<int>(sizeof(original_time_in_ms)),
211                 last_read_buffer_->data_size());
212       original_time_in_ms = *(reinterpret_cast<const double*>(
213           last_read_buffer_->data()));
214       if (original_time_in_ms != time_in_ms)
215         ss << ":" << original_time_in_ms;
216
217       // Detect full-discard preroll buffer.
218       if (last_read_buffer_->discard_padding().first == kInfiniteDuration() &&
219           last_read_buffer_->discard_padding().second == base::TimeDelta()) {
220         ss << "P";
221       }
222     }
223
224     EXPECT_EQ(expected, ss.str());
225     CheckReadStalls(stream);
226   }
227
228   base::MessageLoop message_loop_;
229   StrictMock<FrameProcessorTestCallbackHelper> callbacks_;
230
231   scoped_ptr<FrameProcessor> frame_processor_;
232   base::TimeDelta append_window_start_;
233   base::TimeDelta append_window_end_;
234   bool new_media_segment_;
235   base::TimeDelta timestamp_offset_;
236   scoped_ptr<ChunkDemuxerStream> audio_;
237   scoped_ptr<ChunkDemuxerStream> video_;
238   const TrackId audio_id_;
239   const TrackId video_id_;
240   const base::TimeDelta frame_duration_;  // Currently the same for all streams.
241   const BufferQueue empty_queue_;
242   const TextBufferQueueMap empty_text_buffers_;
243
244   // StoreStatusAndBuffer's most recent result.
245   DemuxerStream::Status last_read_status_;
246   scoped_refptr<DecoderBuffer> last_read_buffer_;
247   bool read_callback_called_;
248
249  private:
250   void StoreStatusAndBuffer(DemuxerStream::Status status,
251                             const scoped_refptr<DecoderBuffer>& buffer) {
252     if (status == DemuxerStream::kOk && buffer) {
253       DVLOG(3) << __FUNCTION__ << "status: " << status << " ts: "
254                << buffer->timestamp().InSecondsF();
255     } else {
256       DVLOG(3) << __FUNCTION__ << "status: " << status << " ts: n/a";
257     }
258
259     read_callback_called_ = true;
260     last_read_status_ = status;
261     last_read_buffer_ = buffer;
262   }
263
264   void CreateAndConfigureStream(DemuxerStream::Type type) {
265     // TODO(wolenetz/dalecurtis): Also test with splicing disabled?
266     switch (type) {
267       case DemuxerStream::AUDIO: {
268         ASSERT_FALSE(audio_);
269         audio_.reset(new ChunkDemuxerStream(DemuxerStream::AUDIO, true));
270         AudioDecoderConfig decoder_config(kCodecVorbis,
271                                           kSampleFormatPlanarF32,
272                                           CHANNEL_LAYOUT_STEREO,
273                                           1000,
274                                           NULL,
275                                           0,
276                                           false);
277         frame_processor_->OnPossibleAudioConfigUpdate(decoder_config);
278         ASSERT_TRUE(
279             audio_->UpdateAudioConfig(decoder_config, base::Bind(&LogFunc)));
280         break;
281       }
282       case DemuxerStream::VIDEO: {
283         ASSERT_FALSE(video_);
284         video_.reset(new ChunkDemuxerStream(DemuxerStream::VIDEO, true));
285         ASSERT_TRUE(video_->UpdateVideoConfig(TestVideoConfig::Normal(),
286                                               base::Bind(&LogFunc)));
287         break;
288       }
289       // TODO(wolenetz): Test text coded frame processing.
290       case DemuxerStream::TEXT:
291       case DemuxerStream::UNKNOWN:
292       case DemuxerStream::NUM_TYPES: {
293         ASSERT_FALSE(true);
294       }
295     }
296   }
297
298   DISALLOW_COPY_AND_ASSIGN(FrameProcessorTest);
299 };
300
301 TEST_F(FrameProcessorTest, WrongTypeInAppendedBuffer) {
302   AddTestTracks(HAS_AUDIO);
303   new_media_segment_ = true;
304
305   ASSERT_FALSE(frame_processor_->ProcessFrames(
306       StringToBufferQueue("0K", audio_id_, DemuxerStream::VIDEO),
307       empty_queue_,
308       empty_text_buffers_,
309       append_window_start_, append_window_end_,
310       &new_media_segment_, &timestamp_offset_));
311   EXPECT_TRUE(new_media_segment_);
312   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
313   CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
314   CheckReadStalls(audio_.get());
315 }
316
317 TEST_F(FrameProcessorTest, NonMonotonicallyIncreasingTimestampInOneCall) {
318   AddTestTracks(HAS_AUDIO);
319   new_media_segment_ = true;
320
321   ASSERT_FALSE(frame_processor_->ProcessFrames(
322       StringToBufferQueue("10K 0K", audio_id_, DemuxerStream::AUDIO),
323       empty_queue_,
324       empty_text_buffers_,
325       append_window_start_, append_window_end_,
326       &new_media_segment_, &timestamp_offset_));
327   EXPECT_TRUE(new_media_segment_);
328   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
329   CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
330   CheckReadStalls(audio_.get());
331 }
332
333 TEST_P(FrameProcessorTest, AudioOnly_SingleFrame) {
334   // Tests A: P(A) -> (a)
335   InSequence s;
336   AddTestTracks(HAS_AUDIO);
337   new_media_segment_ = true;
338   if (GetParam())
339     frame_processor_->SetSequenceMode(true);
340
341   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
342   ProcessFrames("0K", "");
343   EXPECT_FALSE(new_media_segment_);
344   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
345   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) }");
346   CheckReadsThenReadStalls(audio_.get(), "0");
347 }
348
349 TEST_P(FrameProcessorTest, VideoOnly_SingleFrame) {
350   // Tests V: P(V) -> (v)
351   InSequence s;
352   AddTestTracks(HAS_VIDEO);
353   new_media_segment_ = true;
354   if (GetParam())
355     frame_processor_->SetSequenceMode(true);
356
357   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
358   ProcessFrames("", "0K");
359   EXPECT_FALSE(new_media_segment_);
360   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
361   CheckExpectedRangesByTimestamp(video_.get(), "{ [0,10) }");
362   CheckReadsThenReadStalls(video_.get(), "0");
363 }
364
365 TEST_P(FrameProcessorTest, AudioOnly_TwoFrames) {
366   // Tests A: P(A0, A10) -> (a0, a10)
367   InSequence s;
368   AddTestTracks(HAS_AUDIO);
369   new_media_segment_ = true;
370   if (GetParam())
371     frame_processor_->SetSequenceMode(true);
372
373   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 2));
374   ProcessFrames("0K 10K", "");
375   EXPECT_FALSE(new_media_segment_);
376   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
377   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
378   CheckReadsThenReadStalls(audio_.get(), "0 10");
379 }
380
381 TEST_P(FrameProcessorTest, AudioOnly_SetOffsetThenSingleFrame) {
382   // Tests A: STSO(50)+P(A0) -> TSO==50,(a0@50)
383   InSequence s;
384   AddTestTracks(HAS_AUDIO);
385   new_media_segment_ = true;
386   if (GetParam())
387     frame_processor_->SetSequenceMode(true);
388
389   const base::TimeDelta fifty_ms = base::TimeDelta::FromMilliseconds(50);
390   SetTimestampOffset(fifty_ms);
391   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ + fifty_ms));
392   ProcessFrames("0K", "");
393   EXPECT_FALSE(new_media_segment_);
394   EXPECT_EQ(fifty_ms, timestamp_offset_);
395   CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) }");
396
397   // We do not stall on reading without seeking to 50ms due to
398   // SourceBufferStream::kSeekToStartFudgeRoom().
399   CheckReadsThenReadStalls(audio_.get(), "50:0");
400 }
401
402 TEST_P(FrameProcessorTest, AudioOnly_SetOffsetThenFrameTimestampBelowOffset) {
403   // Tests A: STSO(50)+P(A20) ->
404   //   if sequence mode: TSO==30,(a20@50)
405   //   if segments mode: TSO==50,(a20@70)
406   InSequence s;
407   AddTestTracks(HAS_AUDIO);
408   new_media_segment_ = true;
409   bool using_sequence_mode = GetParam();
410   if (using_sequence_mode)
411     frame_processor_->SetSequenceMode(true);
412
413   const base::TimeDelta fifty_ms = base::TimeDelta::FromMilliseconds(50);
414   const base::TimeDelta twenty_ms = base::TimeDelta::FromMilliseconds(20);
415   SetTimestampOffset(fifty_ms);
416
417   if (using_sequence_mode) {
418     EXPECT_CALL(callbacks_, PossibleDurationIncrease(
419         fifty_ms + frame_duration_));
420   } else {
421     EXPECT_CALL(callbacks_, PossibleDurationIncrease(
422         fifty_ms + twenty_ms + frame_duration_));
423   }
424
425   ProcessFrames("20K", "");
426   EXPECT_FALSE(new_media_segment_);
427
428   // We do not stall on reading without seeking to 50ms / 70ms due to
429   // SourceBufferStream::kSeekToStartFudgeRoom().
430   if (using_sequence_mode) {
431     EXPECT_EQ(fifty_ms - twenty_ms, timestamp_offset_);
432     CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) }");
433     CheckReadsThenReadStalls(audio_.get(), "50:20");
434   } else {
435     EXPECT_EQ(fifty_ms, timestamp_offset_);
436     CheckExpectedRangesByTimestamp(audio_.get(), "{ [70,80) }");
437     CheckReadsThenReadStalls(audio_.get(), "70:20");
438   }
439 }
440
441 TEST_P(FrameProcessorTest, AudioOnly_SequentialProcessFrames) {
442   // Tests A: P(A0,A10)+P(A20,A30) -> (a0,a10,a20,a30)
443   InSequence s;
444   AddTestTracks(HAS_AUDIO);
445   new_media_segment_ = true;
446   if (GetParam())
447     frame_processor_->SetSequenceMode(true);
448
449   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 2));
450   ProcessFrames("0K 10K", "");
451   EXPECT_FALSE(new_media_segment_);
452   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
453   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
454
455   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 4));
456   ProcessFrames("20K 30K", "");
457   EXPECT_FALSE(new_media_segment_);
458   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
459   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
460
461   CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
462 }
463
464 TEST_P(FrameProcessorTest, AudioOnly_NonSequentialProcessFrames) {
465   // Tests A: P(A20,A30)+P(A0,A10) ->
466   //   if sequence mode: TSO==-20 after first P(), 20 after second P(), and
467   //                     a(20@0,a30@10,a0@20,a10@30)
468   //   if segments mode: TSO==0,(a0,a10,a20,a30)
469   InSequence s;
470   AddTestTracks(HAS_AUDIO);
471   new_media_segment_ = true;
472   bool using_sequence_mode = GetParam();
473   if (using_sequence_mode) {
474     frame_processor_->SetSequenceMode(true);
475     EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 2));
476   } else {
477     EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 4));
478   }
479
480   ProcessFrames("20K 30K", "");
481   EXPECT_FALSE(new_media_segment_);
482
483   if (using_sequence_mode) {
484     CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
485     EXPECT_EQ(frame_duration_ * -2, timestamp_offset_);
486     EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 4));
487   } else {
488     CheckExpectedRangesByTimestamp(audio_.get(), "{ [20,40) }");
489     EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
490     EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 2));
491   }
492
493   ProcessFrames("0K 10K", "");
494   EXPECT_FALSE(new_media_segment_);
495
496   if (using_sequence_mode) {
497     CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
498     EXPECT_EQ(frame_duration_ * 2, timestamp_offset_);
499     CheckReadsThenReadStalls(audio_.get(), "0:20 10:30 20:0 30:10");
500   } else {
501     CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
502     EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
503     // TODO(wolenetz): Fix this need to seek to 0ms, possibly by having
504     // SourceBufferStream defer initial seek until next read. See
505     // http://crbug.com/371493.
506     audio_->AbortReads();
507     audio_->Seek(base::TimeDelta());
508     audio_->StartReturningData();
509     CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
510   }
511 }
512
513 TEST_P(FrameProcessorTest, AudioVideo_SequentialProcessFrames) {
514   // Tests AV: P(A0,A10;V0k,V10,V20)+P(A20,A30,A40,V30) ->
515   //   (a0,a10,a20,a30,a40);(v0,v10,v20,v30)
516   InSequence s;
517   AddTestTracks(HAS_AUDIO | HAS_VIDEO);
518   new_media_segment_ = true;
519   if (GetParam())
520     frame_processor_->SetSequenceMode(true);
521
522   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 3));
523   ProcessFrames("0K 10K", "0K 10 20");
524   EXPECT_FALSE(new_media_segment_);
525   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
526   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
527   CheckExpectedRangesByTimestamp(video_.get(), "{ [0,30) }");
528
529   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 5));
530   ProcessFrames("20K 30K 40K", "30");
531   EXPECT_FALSE(new_media_segment_);
532   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
533   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,50) }");
534   CheckExpectedRangesByTimestamp(video_.get(), "{ [0,40) }");
535
536   CheckReadsThenReadStalls(audio_.get(), "0 10 20 30 40");
537   CheckReadsThenReadStalls(video_.get(), "0 10 20 30");
538 }
539
540 TEST_P(FrameProcessorTest, AudioVideo_Discontinuity) {
541   // Tests AV: P(A0,A10,A30,A40,A50;V0k,V10,V40,V50key) ->
542   //   if sequence mode: TSO==10,(a0,a10,a30,a40,a50@60);(v0,v10,v50@60)
543   //   if segments mode: TSO==0,(a0,a10,a30,a40,a50);(v0,v10,v50)
544   // This assumes A40K is processed before V40, which depends currently on
545   // MergeBufferQueues() behavior.
546   InSequence s;
547   AddTestTracks(HAS_AUDIO | HAS_VIDEO);
548   new_media_segment_ = true;
549   bool using_sequence_mode = GetParam();
550   if (using_sequence_mode) {
551     frame_processor_->SetSequenceMode(true);
552     EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 7));
553   } else {
554     EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 6));
555   }
556
557   ProcessFrames("0K 10K 30K 40K 50K", "0K 10 40 50K");
558   EXPECT_FALSE(new_media_segment_);
559
560   if (using_sequence_mode) {
561     EXPECT_EQ(frame_duration_, timestamp_offset_);
562     CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,70) }");
563     CheckExpectedRangesByTimestamp(video_.get(), "{ [0,70) }");
564     CheckReadsThenReadStalls(audio_.get(), "0 10 30 40 60:50");
565     CheckReadsThenReadStalls(video_.get(), "0 10 60:50");
566   } else {
567     EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
568     CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,60) }");
569     CheckExpectedRangesByTimestamp(video_.get(), "{ [0,20) [50,60) }");
570     CheckReadsThenReadStalls(audio_.get(), "0 10 30 40 50");
571     CheckReadsThenReadStalls(video_.get(), "0 10");
572     video_->AbortReads();
573     video_->Seek(frame_duration_ * 5);
574     video_->StartReturningData();
575     CheckReadsThenReadStalls(video_.get(), "50");
576   }
577 }
578
579 TEST_P(FrameProcessorTest,
580        AppendWindowFilterOfNegativeBufferTimestampsWithPrerollDiscard) {
581   InSequence s;
582   AddTestTracks(HAS_AUDIO);
583   new_media_segment_ = true;
584   if (GetParam())
585     frame_processor_->SetSequenceMode(true);
586
587   SetTimestampOffset(frame_duration_ * -2);
588   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
589   ProcessFrames("0K 10K 20K", "");
590   EXPECT_FALSE(new_media_segment_);
591   EXPECT_EQ(frame_duration_ * -2, timestamp_offset_);
592   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) }");
593   CheckReadsThenReadStalls(audio_.get(), "0:10P 0:20");
594 }
595
596 TEST_P(FrameProcessorTest, AppendWindowFilterWithInexactPreroll) {
597   InSequence s;
598   AddTestTracks(HAS_AUDIO);
599   new_media_segment_ = true;
600   if (GetParam())
601     frame_processor_->SetSequenceMode(true);
602   SetTimestampOffset(-frame_duration_);
603   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 2));
604   ProcessFrames("0K 9.75K 20K", "");
605   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
606   CheckReadsThenReadStalls(audio_.get(), "0P 0:9.75 10:20");
607 }
608
609 TEST_P(FrameProcessorTest, AppendWindowFilterWithInexactPreroll_2) {
610   InSequence s;
611   AddTestTracks(HAS_AUDIO);
612   new_media_segment_ = true;
613   if (GetParam())
614     frame_processor_->SetSequenceMode(true);
615   SetTimestampOffset(-frame_duration_);
616   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 2));
617   ProcessFrames("0K 10.25K 20K", "");
618   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
619   CheckReadsThenReadStalls(audio_.get(), "0P 0:10.25 10:20");
620 }
621
622 TEST_P(FrameProcessorTest, AllowNegativeFramePTSAndDTSBeforeOffsetAdjustment) {
623   InSequence s;
624   AddTestTracks(HAS_AUDIO);
625   new_media_segment_ = true;
626   bool using_sequence_mode = GetParam();
627   if (using_sequence_mode) {
628     frame_processor_->SetSequenceMode(true);
629     EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 3));
630   } else {
631     EXPECT_CALL(callbacks_,
632                 PossibleDurationIncrease((frame_duration_ * 5) / 2));
633   }
634
635   ProcessFrames("-5K 5K 15K", "");
636
637   if (using_sequence_mode) {
638     EXPECT_EQ(frame_duration_ / 2, timestamp_offset_);
639     CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,30) }");
640     CheckReadsThenReadStalls(audio_.get(), "0:-5 10:5 20:15");
641   } else {
642     EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
643     CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,25) }");
644     CheckReadsThenReadStalls(audio_.get(), "0:-5 5 15");
645   }
646 }
647
648 TEST_P(FrameProcessorTest, PartialAppendWindowFilterNoDiscontinuity) {
649   // Tests that spurious discontinuity is not introduced by a partially
650   // trimmed frame.
651   InSequence s;
652   AddTestTracks(HAS_AUDIO);
653   new_media_segment_ = true;
654   if (GetParam())
655     frame_processor_->SetSequenceMode(true);
656   EXPECT_CALL(callbacks_,
657               PossibleDurationIncrease(base::TimeDelta::FromMilliseconds(29)));
658
659   append_window_start_ = base::TimeDelta::FromMilliseconds(7);
660   ProcessFrames("0K 19K", "");
661
662   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
663   CheckExpectedRangesByTimestamp(audio_.get(), "{ [7,29) }");
664   CheckReadsThenReadStalls(audio_.get(), "7:0 19");
665 }
666
667 INSTANTIATE_TEST_CASE_P(SequenceMode, FrameProcessorTest, Values(true));
668 INSTANTIATE_TEST_CASE_P(SegmentsMode, FrameProcessorTest, Values(false));
669
670 }  // namespace media