Home | History | Annotate | Download | only in filters
      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.get()) {
    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 TEST_P(FrameProcessorTest, PartialAppendWindowFilterNoNewMediaSegment) {
    668   // Tests that a new media segment is not forcibly signalled for audio frame
    669   // partial front trim, to prevent incorrect introduction of a discontinuity
    670   // and potentially a non-keyframe video frame to be processed next after the
    671   // discontinuity.
    672   InSequence s;
    673   AddTestTracks(HAS_AUDIO | HAS_VIDEO);
    674   new_media_segment_ = true;
    675   frame_processor_->SetSequenceMode(GetParam());
    676   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
    677   ProcessFrames("", "0K");
    678   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
    679   ProcessFrames("-5K", "");
    680   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_* 2));
    681   ProcessFrames("", "10");
    682 
    683   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
    684   EXPECT_FALSE(new_media_segment_);
    685   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,5) }");
    686   CheckExpectedRangesByTimestamp(video_.get(), "{ [0,20) }");
    687   CheckReadsThenReadStalls(audio_.get(), "0:-5");
    688   CheckReadsThenReadStalls(video_.get(), "0 10");
    689 }
    690 
    691 INSTANTIATE_TEST_CASE_P(SequenceMode, FrameProcessorTest, Values(true));
    692 INSTANTIATE_TEST_CASE_P(SegmentsMode, FrameProcessorTest, Values(false));
    693 
    694 }  // namespace media
    695