| Index: media/filters/source_buffer_stream_unittest.cc
 | 
| diff --git a/media/filters/source_buffer_stream_unittest.cc b/media/filters/source_buffer_stream_unittest.cc
 | 
| index 3d03ccd16867f6c662ee0fa28e3e2e31fcf045bb..8f518766472019feeb22b8a3db31858c459fc0bf 100644
 | 
| --- a/media/filters/source_buffer_stream_unittest.cc
 | 
| +++ b/media/filters/source_buffer_stream_unittest.cc
 | 
| @@ -15,11 +15,21 @@
 | 
|  #include "base/strings/string_util.h"
 | 
|  #include "media/base/data_buffer.h"
 | 
|  #include "media/base/media_log.h"
 | 
| +#include "media/base/mock_media_log.h"
 | 
|  #include "media/base/test_helpers.h"
 | 
|  #include "media/base/text_track_config.h"
 | 
|  #include "media/filters/webvtt_util.h"
 | 
|  #include "testing/gtest/include/gtest/gtest.h"
 | 
|  
 | 
| +using ::testing::HasSubstr;
 | 
| +using ::testing::InSequence;
 | 
| +using ::testing::StrictMock;
 | 
| +
 | 
| +// Helper macros to reduce boilerplate when verifying media log entries.
 | 
| +#define EXPECT_MEDIA_LOG_STRING(x) \
 | 
| +  EXPECT_CALL(*media_log_, DoAddEventLogString((x)))
 | 
| +#define CONTAINS_STRING(arg, x) (std::string::npos != (arg).find(x))
 | 
| +
 | 
|  namespace media {
 | 
|  
 | 
|  typedef StreamParser::BufferQueue BufferQueue;
 | 
| @@ -30,12 +40,46 @@ static const uint8 kDataA = 0x11;
 | 
|  static const uint8 kDataB = 0x33;
 | 
|  static const int kDataSize = 1;
 | 
|  
 | 
| +// Matchers for verifying common media log entry strings.
 | 
| +MATCHER(ContainsMissingKeyframeLog, "") {
 | 
| +  return CONTAINS_STRING(arg,
 | 
| +                         "Media segment did not begin with key frame. Support "
 | 
| +                         "for such segments will be available in a future "
 | 
| +                         "version. Please see https://crbug.com/229412.");
 | 
| +}
 | 
| +
 | 
| +MATCHER(ContainsSameTimestampAt30MillisecondsLog, "") {
 | 
| +  return CONTAINS_STRING(arg,
 | 
| +                         "Unexpected combination of buffers with the same "
 | 
| +                         "timestamp detected at 0.03");
 | 
| +}
 | 
| +
 | 
| +MATCHER_P(ContainsTrackBufferExhaustionSkipLog, skip_milliseconds, "") {
 | 
| +  return CONTAINS_STRING(arg,
 | 
| +                         "Media append that overlapped current playback "
 | 
| +                         "position caused time gap in playing VIDEO stream "
 | 
| +                         "because the next keyframe is " +
 | 
| +                             base::IntToString(skip_milliseconds) +
 | 
| +                             "ms beyond last overlapped frame. Media may "
 | 
| +                             "appear temporarily frozen.");
 | 
| +}
 | 
| +
 | 
| +MATCHER_P2(ContainsGeneratedSpliceLog,
 | 
| +           duration_microseconds,
 | 
| +           time_microseconds,
 | 
| +           "") {
 | 
| +  return CONTAINS_STRING(arg, "Generated splice of overlap duration " +
 | 
| +                                  base::IntToString(duration_microseconds) +
 | 
| +                                  "us into new buffer at " +
 | 
| +                                  base::IntToString(time_microseconds) + "us.");
 | 
| +}
 | 
| +
 | 
|  class SourceBufferStreamTest : public testing::Test {
 | 
|   protected:
 | 
| -  SourceBufferStreamTest() {
 | 
| +  SourceBufferStreamTest() : media_log_(new StrictMock<MockMediaLog>()) {
 | 
|      video_config_ = TestVideoConfig::Normal();
 | 
|      SetStreamInfo(kDefaultFramesPerSecond, kDefaultKeyframesPerSecond);
 | 
| -    stream_.reset(new SourceBufferStream(video_config_, new MediaLog(), true));
 | 
| +    stream_.reset(new SourceBufferStream(video_config_, media_log_, true));
 | 
|    }
 | 
|  
 | 
|    void SetMemoryLimit(size_t buffers_of_data) {
 | 
| @@ -51,7 +95,7 @@ class SourceBufferStreamTest : public testing::Test {
 | 
|    void SetTextStream() {
 | 
|      video_config_ = TestVideoConfig::Invalid();
 | 
|      TextTrackConfig config(kTextSubtitles, "", "", "");
 | 
| -    stream_.reset(new SourceBufferStream(config, new MediaLog(), true));
 | 
| +    stream_.reset(new SourceBufferStream(config, media_log_, true));
 | 
|      SetStreamInfo(2, 2);
 | 
|    }
 | 
|  
 | 
| @@ -67,7 +111,7 @@ class SourceBufferStreamTest : public testing::Test {
 | 
|                               false,
 | 
|                               base::TimeDelta(),
 | 
|                               0);
 | 
| -    stream_.reset(new SourceBufferStream(audio_config_, new MediaLog(), true));
 | 
| +    stream_.reset(new SourceBufferStream(audio_config_, media_log_, true));
 | 
|  
 | 
|      // Equivalent to 2ms per frame.
 | 
|      SetStreamInfo(500, 500);
 | 
| @@ -375,6 +419,7 @@ class SourceBufferStreamTest : public testing::Test {
 | 
|    scoped_ptr<SourceBufferStream> stream_;
 | 
|    VideoDecoderConfig video_config_;
 | 
|    AudioDecoderConfig audio_config_;
 | 
| +  scoped_refptr<StrictMock<MockMediaLog>> media_log_;
 | 
|  
 | 
|   private:
 | 
|    base::TimeDelta ConvertToFrameDuration(int frames_per_second) {
 | 
| @@ -726,6 +771,8 @@ TEST_F(SourceBufferStreamTest, Append_AdjacentRanges) {
 | 
|  }
 | 
|  
 | 
|  TEST_F(SourceBufferStreamTest, Append_DoesNotBeginWithKeyframe) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsMissingKeyframeLog()).Times(2);
 | 
| +
 | 
|    // Append fails because the range doesn't begin with a keyframe.
 | 
|    NewSegmentAppend_ExpectFailure(3, 2);
 | 
|  
 | 
| @@ -747,6 +794,8 @@ TEST_F(SourceBufferStreamTest, Append_DoesNotBeginWithKeyframe) {
 | 
|  }
 | 
|  
 | 
|  TEST_F(SourceBufferStreamTest, Append_DoesNotBeginWithKeyframe_Adjacent) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsMissingKeyframeLog());
 | 
| +
 | 
|    // Append 8 buffers at positions 0 through 7.
 | 
|    NewSegmentAppend(0, 8);
 | 
|  
 | 
| @@ -1412,6 +1461,8 @@ TEST_F(SourceBufferStreamTest, End_Overlap_Selected_NoKeyframeAfterNew) {
 | 
|  // after: |A a a a a A|       |B b b b b B|
 | 
|  // track:                                 |a|
 | 
|  TEST_F(SourceBufferStreamTest, End_Overlap_Selected_NoKeyframeAfterNew2) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsTrackBufferExhaustionSkipLog(133));
 | 
| +
 | 
|    // Append 7 buffers at positions 10 through 16.
 | 
|    NewSegmentAppend(10, 7, &kDataA);
 | 
|  
 | 
| @@ -1676,6 +1727,8 @@ TEST_F(SourceBufferStreamTest, Overlap_OneByOne_BetweenMediaSegments) {
 | 
|  // new  : 0K   30   60   90   120K
 | 
|  // after: 0K   30   60   90  *120K*   130K
 | 
|  TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsTrackBufferExhaustionSkipLog(50));
 | 
| +
 | 
|    NewSegmentAppendOneByOne("10K 40 70 100K 125 130D30K");
 | 
|    CheckExpectedRangesByTimestamp("{ [10,160) }");
 | 
|  
 | 
| @@ -1706,6 +1759,8 @@ TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer) {
 | 
|  // new  :                     110K    130
 | 
|  // after: 0K   30   60   90  *110K*   130
 | 
|  TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer2) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsTrackBufferExhaustionSkipLog(40));
 | 
| +
 | 
|    NewSegmentAppendOneByOne("10K 40 70 100K 125 130D30K");
 | 
|    CheckExpectedRangesByTimestamp("{ [10,160) }");
 | 
|  
 | 
| @@ -1736,6 +1791,8 @@ TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer2) {
 | 
|  // after: 0K   30   50K   80   110   140 * (waiting for keyframe)
 | 
|  // track:             70
 | 
|  TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer3) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsTrackBufferExhaustionSkipLog(80));
 | 
| +
 | 
|    NewSegmentAppendOneByOne("10K 40 70 100K 125 130D30K");
 | 
|    CheckExpectedRangesByTimestamp("{ [10,160) }");
 | 
|  
 | 
| @@ -1831,6 +1888,8 @@ TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer5) {
 | 
|  // after: 0K   30   60   90  *120K*   130K ... 200K 230 260K 290
 | 
|  // track:             70
 | 
|  TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer6) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsTrackBufferExhaustionSkipLog(50));
 | 
| +
 | 
|    NewSegmentAppendOneByOne("10K 40 70 100K 125 130D30K");
 | 
|    NewSegmentAppendOneByOne("200K 230");
 | 
|    CheckExpectedRangesByTimestamp("{ [10,160) [200,260) }");
 | 
| @@ -2603,6 +2662,8 @@ TEST_F(SourceBufferStreamTest, GarbageCollection_NeedsMoreData) {
 | 
|  }
 | 
|  
 | 
|  TEST_F(SourceBufferStreamTest, GarbageCollection_TrackBuffer) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsTrackBufferExhaustionSkipLog(99));
 | 
| +
 | 
|    // Set memory limit to 3 buffers.
 | 
|    SetMemoryLimit(3);
 | 
|  
 | 
| @@ -3352,12 +3413,16 @@ TEST_F(SourceBufferStreamTest, SameTimestamp_Video_TwoAppends) {
 | 
|  // Verify that a non-keyframe followed by a keyframe with the same timestamp
 | 
|  // is not allowed.
 | 
|  TEST_F(SourceBufferStreamTest, SameTimestamp_Video_Invalid_1) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsSameTimestampAt30MillisecondsLog());
 | 
| +
 | 
|    Seek(0);
 | 
|    NewSegmentAppend("0K 30");
 | 
|    AppendBuffers_ExpectFailure("30K 60");
 | 
|  }
 | 
|  
 | 
|  TEST_F(SourceBufferStreamTest, SameTimestamp_Video_Invalid_2) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsSameTimestampAt30MillisecondsLog());
 | 
| +
 | 
|    Seek(0);
 | 
|    NewSegmentAppend_ExpectFailure("0K 30 30K 60");
 | 
|  }
 | 
| @@ -3408,16 +3473,18 @@ TEST_F(SourceBufferStreamTest, SameTimestamp_Video_Overlap_3) {
 | 
|  TEST_F(SourceBufferStreamTest, SameTimestamp_Audio) {
 | 
|    AudioDecoderConfig config(kCodecMP3, kSampleFormatF32, CHANNEL_LAYOUT_STEREO,
 | 
|                              44100, NULL, 0, false);
 | 
| -  stream_.reset(new SourceBufferStream(config, new MediaLog(), true));
 | 
| +  stream_.reset(new SourceBufferStream(config, media_log_, true));
 | 
|    Seek(0);
 | 
|    NewSegmentAppend("0K 0K 30K 30 60 60");
 | 
|    CheckExpectedBuffers("0K 0K 30K 30 60 60");
 | 
|  }
 | 
|  
 | 
|  TEST_F(SourceBufferStreamTest, SameTimestamp_Audio_Invalid_1) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsSameTimestampAt30MillisecondsLog());
 | 
| +
 | 
|    AudioDecoderConfig config(kCodecMP3, kSampleFormatF32, CHANNEL_LAYOUT_STEREO,
 | 
|                              44100, NULL, 0, false);
 | 
| -  stream_.reset(new SourceBufferStream(config, new MediaLog(), true));
 | 
| +  stream_.reset(new SourceBufferStream(config, media_log_, true));
 | 
|    Seek(0);
 | 
|    NewSegmentAppend_ExpectFailure("0K 30 30K 60");
 | 
|  }
 | 
| @@ -3894,6 +3961,8 @@ TEST_F(SourceBufferStreamTest,
 | 
|  }
 | 
|  
 | 
|  TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_Basic) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsGeneratedSpliceLog(3000, 11000));
 | 
| +
 | 
|    SetAudioStream();
 | 
|    Seek(0);
 | 
|    NewSegmentAppend("0K 2K 4K 6K 8K 10K 12K");
 | 
| @@ -3903,6 +3972,10 @@ TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_Basic) {
 | 
|  }
 | 
|  
 | 
|  TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_NoExactSplices) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(
 | 
| +      HasSubstr("Skipping splice frame generation: first new buffer at 10000us "
 | 
| +                "begins at or before existing buffer at 10000us."));
 | 
| +
 | 
|    SetAudioStream();
 | 
|    Seek(0);
 | 
|    NewSegmentAppend("0K 2K 4K 6K 8K 10K 12K");
 | 
| @@ -3913,6 +3986,12 @@ TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_NoExactSplices) {
 | 
|  
 | 
|  // Do not allow splices on top of splices.
 | 
|  TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_NoDoubleSplice) {
 | 
| +  InSequence s;
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsGeneratedSpliceLog(3000, 11000));
 | 
| +  EXPECT_MEDIA_LOG_STRING(
 | 
| +      HasSubstr("Skipping splice frame generation: overlapped buffers at "
 | 
| +                "10000us are in a previously buffered splice."));
 | 
| +
 | 
|    SetAudioStream();
 | 
|    Seek(0);
 | 
|    NewSegmentAppend("0K 2K 4K 6K 8K 10K 12K");
 | 
| @@ -3944,6 +4023,8 @@ TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_NoSplice) {
 | 
|  }
 | 
|  
 | 
|  TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_CorrectMediaSegmentStartTime) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsGeneratedSpliceLog(5000, 1000));
 | 
| +
 | 
|    SetAudioStream();
 | 
|    Seek(0);
 | 
|    NewSegmentAppend("0K 2K 4K");
 | 
| @@ -3957,6 +4038,8 @@ TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_CorrectMediaSegmentStartTime) {
 | 
|  }
 | 
|  
 | 
|  TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_ConfigChange) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsGeneratedSpliceLog(3000, 5000));
 | 
| +
 | 
|    SetAudioStream();
 | 
|  
 | 
|    AudioDecoderConfig new_config(kCodecVorbis,
 | 
| @@ -3980,6 +4063,10 @@ TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_ConfigChange) {
 | 
|  
 | 
|  // Ensure splices are not created if there are not enough frames to crossfade.
 | 
|  TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_NoTinySplices) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(HasSubstr(
 | 
| +      "Skipping splice frame generation: not enough samples for splicing new "
 | 
| +      "buffer at 1000us. Have 1000us, but need 2000us."));
 | 
| +
 | 
|    SetAudioStream();
 | 
|    Seek(0);
 | 
|  
 | 
| @@ -3996,11 +4083,15 @@ TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_NoTinySplices) {
 | 
|  }
 | 
|  
 | 
|  TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_NoMillisecondSplices) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(
 | 
| +      HasSubstr("Skipping splice frame generation: not enough samples for "
 | 
| +                "splicing new buffer at 1250us. Have 750us, but need 1000us."));
 | 
| +
 | 
|    video_config_ = TestVideoConfig::Invalid();
 | 
|    audio_config_.Initialize(kCodecVorbis, kSampleFormatPlanarF32,
 | 
|                             CHANNEL_LAYOUT_STEREO, 4000, NULL, 0, false, false,
 | 
|                             base::TimeDelta(), 0);
 | 
| -  stream_.reset(new SourceBufferStream(audio_config_, new MediaLog(), true));
 | 
| +  stream_.reset(new SourceBufferStream(audio_config_, media_log_, true));
 | 
|    // Equivalent to 0.5ms per frame.
 | 
|    SetStreamInfo(2000, 2000);
 | 
|    Seek(0);
 | 
| @@ -4023,6 +4114,8 @@ TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_NoMillisecondSplices) {
 | 
|  }
 | 
|  
 | 
|  TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_Preroll) {
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsGeneratedSpliceLog(3000, 11000));
 | 
| +
 | 
|    SetAudioStream();
 | 
|    Seek(0);
 | 
|    NewSegmentAppend("0K 2K 4K 6K 8K 10K 12K");
 | 
| @@ -4285,6 +4378,64 @@ TEST_F(SourceBufferStreamTest, ConfigChange_ReSeek) {
 | 
|    CheckVideoConfig(new_config);
 | 
|  }
 | 
|  
 | 
| +TEST_F(SourceBufferStreamTest, TrackBuffer_ExhaustionWithSkipForward) {
 | 
| +  NewSegmentAppend("0K 10 20 30 40");
 | 
| +
 | 
| +  // Read the first 4 buffers, so next buffer is at time 40.
 | 
| +  Seek(0);
 | 
| +  CheckExpectedRangesByTimestamp("{ [0,50) }");
 | 
| +  CheckExpectedBuffers("0K 10 20 30");
 | 
| +
 | 
| +  // Overlap-append, populating track buffer with timestamp 40 from original
 | 
| +  // append. Confirm there could be a large jump in time until the next key
 | 
| +  // frame after exhausting the track buffer.
 | 
| +  NewSegmentAppend(
 | 
| +      "31K 41 51 61 71 81 91 101 111 121 "
 | 
| +      "131K 141");
 | 
| +  CheckExpectedRangesByTimestamp("{ [0,151) }");
 | 
| +
 | 
| +  // Confirm the large jump occurs and warning log is generated.
 | 
| +  // If this test is changed, update
 | 
| +  // TrackBufferExhaustion_ImmediateNewTrackBuffer accordingly.
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsTrackBufferExhaustionSkipLog(91));
 | 
| +
 | 
| +  CheckExpectedBuffers("40 131K 141");
 | 
| +  CheckNoNextBuffer();
 | 
| +}
 | 
| +
 | 
| +TEST_F(SourceBufferStreamTest,
 | 
| +       TrackBuffer_ExhaustionAndImmediateNewTrackBuffer) {
 | 
| +  NewSegmentAppend("0K 10 20 30 40");
 | 
| +
 | 
| +  // Read the first 4 buffers, so next buffer is at time 40.
 | 
| +  Seek(0);
 | 
| +  CheckExpectedRangesByTimestamp("{ [0,50) }");
 | 
| +  CheckExpectedBuffers("0K 10 20 30");
 | 
| +
 | 
| +  // Overlap-append
 | 
| +  NewSegmentAppend(
 | 
| +      "31K 41 51 61 71 81 91 101 111 121 "
 | 
| +      "131K 141");
 | 
| +  CheckExpectedRangesByTimestamp("{ [0,151) }");
 | 
| +
 | 
| +  // Exhaust the track buffer, but don't read any of the overlapping append yet.
 | 
| +  CheckExpectedBuffers("40");
 | 
| +
 | 
| +  // Selected range's next buffer is now the 131K buffer from the overlapping
 | 
| +  // append. (See TrackBuffer_ExhaustionWithSkipForward for that verification.)
 | 
| +  // Do another overlap-append to immediately create another track buffer and
 | 
| +  // verify both track buffer exhaustions skip forward and emit log warnings.
 | 
| +  NewSegmentAppend("22K 32 42 52 62 72 82 92 102 112 122K 132 142 152K 162");
 | 
| +  CheckExpectedRangesByTimestamp("{ [0,172) }");
 | 
| +
 | 
| +  InSequence s;
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsTrackBufferExhaustionSkipLog(91));
 | 
| +  EXPECT_MEDIA_LOG_STRING(ContainsTrackBufferExhaustionSkipLog(11));
 | 
| +
 | 
| +  CheckExpectedBuffers("131K 141 152K 162");
 | 
| +  CheckNoNextBuffer();
 | 
| +}
 | 
| +
 | 
|  // TODO(vrk): Add unit tests where keyframes are unaligned between streams.
 | 
|  // (crbug.com/133557)
 | 
|  
 | 
| 
 |