1// Copyright (c) 2012 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 "media/filters/pipeline_integration_test_base.h"
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/strings/string_util.h"
11#include "build/build_config.h"
12#include "media/base/cdm_promise.h"
13#include "media/base/decoder_buffer.h"
14#include "media/base/media_keys.h"
15#include "media/base/media_switches.h"
16#include "media/base/test_data_util.h"
17#include "media/cdm/aes_decryptor.h"
18#include "media/cdm/json_web_key.h"
19#include "media/filters/chunk_demuxer.h"
20#include "media/filters/renderer_impl.h"
21#include "testing/gmock/include/gmock/gmock.h"
22
23using testing::_;
24using testing::AnyNumber;
25using testing::AtLeast;
26using testing::AtMost;
27using testing::SaveArg;
28
29namespace media {
30
31const char kSourceId[] = "SourceId";
32const uint8 kInitData[] = { 0x69, 0x6e, 0x69, 0x74 };
33
34const char kWebM[] = "video/webm; codecs=\"vp8,vorbis\"";
35const char kWebMVP9[] = "video/webm; codecs=\"vp9\"";
36const char kAudioOnlyWebM[] = "video/webm; codecs=\"vorbis\"";
37const char kOpusAudioOnlyWebM[] = "video/webm; codecs=\"opus\"";
38const char kVideoOnlyWebM[] = "video/webm; codecs=\"vp8\"";
39const char kMP4VideoType[] = "video/mp4";
40const char kMP4AudioType[] = "audio/mp4";
41#if defined(USE_PROPRIETARY_CODECS)
42const char kADTS[] = "audio/aac";
43const char kMP4[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\"";
44const char kMP4Video[] = "video/mp4; codecs=\"avc1.4D4041\"";
45const char kMP4VideoAVC3[] = "video/mp4; codecs=\"avc3.64001f\"";
46const char kMP4Audio[] = "audio/mp4; codecs=\"mp4a.40.2\"";
47const char kMP3[] = "audio/mpeg";
48#endif  // defined(USE_PROPRIETARY_CODECS)
49
50// Key used to encrypt test files.
51const uint8 kSecretKey[] = {
52  0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
53  0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
54};
55
56// The key ID for all encrypted files.
57const uint8 kKeyId[] = {
58  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
59  0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35
60};
61
62const int kAppendWholeFile = -1;
63
64// Constants for the Media Source config change tests.
65const int kAppendTimeSec = 1;
66const int kAppendTimeMs = kAppendTimeSec * 1000;
67const int k320WebMFileDurationMs = 2736;
68const int k640WebMFileDurationMs = 2749;
69const int kOpusEndTrimmingWebMFileDurationMs = 2741;
70const int kVP9WebMFileDurationMs = 2736;
71const int kVP8AWebMFileDurationMs = 2733;
72
73#if defined(USE_PROPRIETARY_CODECS)
74const int k640IsoFileDurationMs = 2737;
75const int k640IsoCencFileDurationMs = 2736;
76const int k1280IsoFileDurationMs = 2736;
77const int k1280IsoAVC3FileDurationMs = 2736;
78#endif  // defined(USE_PROPRIETARY_CODECS)
79
80// Return a timeline offset for bear-320x240-live.webm.
81static base::Time kLiveTimelineOffset() {
82  // The file contians the following UTC timeline offset:
83  // 2012-11-10 12:34:56.789123456
84  // Since base::Time only has a resolution of microseconds,
85  // construct a base::Time for 2012-11-10 12:34:56.789123.
86  base::Time::Exploded exploded_time;
87  exploded_time.year = 2012;
88  exploded_time.month = 11;
89  exploded_time.day_of_month = 10;
90  exploded_time.hour = 12;
91  exploded_time.minute = 34;
92  exploded_time.second = 56;
93  exploded_time.millisecond = 789;
94  base::Time timeline_offset = base::Time::FromUTCExploded(exploded_time);
95
96  timeline_offset += base::TimeDelta::FromMicroseconds(123);
97
98  return timeline_offset;
99}
100
101// FFmpeg only supports time a resolution of seconds so this
102// helper function truncates a base::Time to seconds resolution.
103static base::Time TruncateToFFmpegTimeResolution(base::Time t) {
104  base::Time::Exploded exploded_time;
105  t.UTCExplode(&exploded_time);
106  exploded_time.millisecond = 0;
107
108  return base::Time::FromUTCExploded(exploded_time);
109}
110
111// Note: Tests using this class only exercise the DecryptingDemuxerStream path.
112// They do not exercise the Decrypting{Audio|Video}Decoder path.
113class FakeEncryptedMedia {
114 public:
115  // Defines the behavior of the "app" that responds to EME events.
116  class AppBase {
117   public:
118    virtual ~AppBase() {}
119
120    virtual void OnSessionMessage(const std::string& web_session_id,
121                                  const std::vector<uint8>& message,
122                                  const GURL& destination_url) = 0;
123
124    virtual void OnSessionClosed(const std::string& web_session_id) = 0;
125
126    virtual void OnSessionKeysChange(const std::string& web_session_id,
127                                     bool has_additional_usable_key) = 0;
128
129    // Errors are not expected unless overridden.
130    virtual void OnSessionError(const std::string& web_session_id,
131                                const std::string& error_name,
132                                uint32 system_code,
133                                const std::string& error_message) {
134      FAIL() << "Unexpected Key Error";
135    }
136
137    virtual void NeedKey(const std::string& type,
138                         const std::vector<uint8>& init_data,
139                         AesDecryptor* decryptor) = 0;
140  };
141
142  FakeEncryptedMedia(AppBase* app)
143      : decryptor_(base::Bind(&FakeEncryptedMedia::OnSessionMessage,
144                              base::Unretained(this)),
145                   base::Bind(&FakeEncryptedMedia::OnSessionClosed,
146                              base::Unretained(this)),
147                   base::Bind(&FakeEncryptedMedia::OnSessionKeysChange,
148                              base::Unretained(this))),
149        app_(app) {}
150
151  AesDecryptor* decryptor() {
152    return &decryptor_;
153  }
154
155  // Callbacks for firing session events. Delegate to |app_|.
156  void OnSessionMessage(const std::string& web_session_id,
157                        const std::vector<uint8>& message,
158                        const GURL& destination_url) {
159    app_->OnSessionMessage(web_session_id, message, destination_url);
160  }
161
162  void OnSessionClosed(const std::string& web_session_id) {
163    app_->OnSessionClosed(web_session_id);
164  }
165
166  void OnSessionKeysChange(const std::string& web_session_id,
167                           bool has_additional_usable_key) {
168    app_->OnSessionKeysChange(web_session_id, has_additional_usable_key);
169  }
170
171  void OnSessionError(const std::string& web_session_id,
172                      const std::string& error_name,
173                      uint32 system_code,
174                      const std::string& error_message) {
175    app_->OnSessionError(
176        web_session_id, error_name, system_code, error_message);
177  }
178
179  void NeedKey(const std::string& type,
180               const std::vector<uint8>& init_data) {
181    app_->NeedKey(type, init_data, &decryptor_);
182  }
183
184 private:
185  AesDecryptor decryptor_;
186  scoped_ptr<AppBase> app_;
187};
188
189enum PromiseResult { RESOLVED, REJECTED };
190
191// Provides |kSecretKey| in response to needkey.
192class KeyProvidingApp : public FakeEncryptedMedia::AppBase {
193 public:
194  KeyProvidingApp() {}
195
196  void OnResolveWithSession(PromiseResult expected,
197                            const std::string& web_session_id) {
198    EXPECT_EQ(expected, RESOLVED);
199    EXPECT_GT(web_session_id.length(), 0ul);
200    current_session_id_ = web_session_id;
201  }
202
203  void OnResolve(PromiseResult expected) {
204    EXPECT_EQ(expected, RESOLVED);
205  }
206
207  void OnReject(PromiseResult expected,
208                media::MediaKeys::Exception exception_code,
209                uint32 system_code,
210                const std::string& error_message) {
211    EXPECT_EQ(expected, REJECTED);
212  }
213
214  scoped_ptr<SimpleCdmPromise> CreatePromise(PromiseResult expected) {
215    scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
216        base::Bind(
217            &KeyProvidingApp::OnResolve, base::Unretained(this), expected),
218        base::Bind(
219            &KeyProvidingApp::OnReject, base::Unretained(this), expected)));
220    return promise.Pass();
221  }
222
223  scoped_ptr<NewSessionCdmPromise> CreateSessionPromise(
224      PromiseResult expected) {
225    scoped_ptr<media::NewSessionCdmPromise> promise(
226        new media::NewSessionCdmPromise(
227            base::Bind(&KeyProvidingApp::OnResolveWithSession,
228                       base::Unretained(this),
229                       expected),
230            base::Bind(
231                &KeyProvidingApp::OnReject, base::Unretained(this), expected)));
232    return promise.Pass();
233  }
234
235  virtual void OnSessionMessage(const std::string& web_session_id,
236                                const std::vector<uint8>& message,
237                                const GURL& destination_url) OVERRIDE {
238    EXPECT_FALSE(web_session_id.empty());
239    EXPECT_FALSE(message.empty());
240    EXPECT_EQ(current_session_id_, web_session_id);
241  }
242
243  virtual void OnSessionClosed(const std::string& web_session_id) OVERRIDE {
244    EXPECT_EQ(current_session_id_, web_session_id);
245  }
246
247  virtual void OnSessionKeysChange(const std::string& web_session_id,
248                                   bool has_additional_usable_key) OVERRIDE {
249    EXPECT_EQ(current_session_id_, web_session_id);
250    EXPECT_EQ(has_additional_usable_key, true);
251  }
252
253  virtual void NeedKey(const std::string& type,
254                       const std::vector<uint8>& init_data,
255                       AesDecryptor* decryptor) OVERRIDE {
256    if (current_session_id_.empty()) {
257      decryptor->CreateSession(type,
258                               kInitData,
259                               arraysize(kInitData),
260                               MediaKeys::TEMPORARY_SESSION,
261                               CreateSessionPromise(RESOLVED));
262      EXPECT_FALSE(current_session_id_.empty());
263    }
264
265    // Clear Key really needs the key ID in |init_data|. For WebM, they are the
266    // same, but this is not the case for ISO CENC. Therefore, provide the
267    // correct key ID.
268    const uint8* key_id = init_data.empty() ? NULL : &init_data[0];
269    size_t key_id_length = init_data.size();
270    if (type == kMP4AudioType || type == kMP4VideoType) {
271      key_id = kKeyId;
272      key_id_length = arraysize(kKeyId);
273    }
274
275    // Convert key into a JSON structure and then add it.
276    std::string jwk = GenerateJWKSet(
277        kSecretKey, arraysize(kSecretKey), key_id, key_id_length);
278    decryptor->UpdateSession(current_session_id_,
279                             reinterpret_cast<const uint8*>(jwk.data()),
280                             jwk.size(),
281                             CreatePromise(RESOLVED));
282  }
283
284  std::string current_session_id_;
285};
286
287class RotatingKeyProvidingApp : public KeyProvidingApp {
288 public:
289  RotatingKeyProvidingApp() : num_distint_need_key_calls_(0) {}
290  virtual ~RotatingKeyProvidingApp() {
291    // Expect that NeedKey is fired multiple times with different |init_data|.
292    EXPECT_GT(num_distint_need_key_calls_, 1u);
293  }
294
295  virtual void NeedKey(const std::string& type,
296                       const std::vector<uint8>& init_data,
297                       AesDecryptor* decryptor) OVERRIDE {
298    // Skip the request if the |init_data| has been seen.
299    if (init_data == prev_init_data_)
300      return;
301    prev_init_data_ = init_data;
302    ++num_distint_need_key_calls_;
303
304    decryptor->CreateSession(type,
305                             vector_as_array(&init_data),
306                             init_data.size(),
307                             MediaKeys::TEMPORARY_SESSION,
308                             CreateSessionPromise(RESOLVED));
309
310    std::vector<uint8> key_id;
311    std::vector<uint8> key;
312    EXPECT_TRUE(GetKeyAndKeyId(init_data, &key, &key_id));
313
314    // Convert key into a JSON structure and then add it.
315    std::string jwk = GenerateJWKSet(vector_as_array(&key),
316                                     key.size(),
317                                     vector_as_array(&key_id),
318                                     key_id.size());
319    decryptor->UpdateSession(current_session_id_,
320                             reinterpret_cast<const uint8*>(jwk.data()),
321                             jwk.size(),
322                             CreatePromise(RESOLVED));
323  }
324
325 private:
326  bool GetKeyAndKeyId(std::vector<uint8> init_data,
327                      std::vector<uint8>* key,
328                      std::vector<uint8>* key_id) {
329    // For WebM, init_data is key_id; for ISO CENC, init_data should contain
330    // the key_id. We assume key_id is in the end of init_data here (that is
331    // only a reasonable assumption for WebM and clear key ISO CENC).
332    DCHECK_GE(init_data.size(), arraysize(kKeyId));
333    std::vector<uint8> key_id_from_init_data(
334        init_data.end() - arraysize(kKeyId), init_data.end());
335
336    key->assign(kSecretKey, kSecretKey + arraysize(kSecretKey));
337    key_id->assign(kKeyId, kKeyId + arraysize(kKeyId));
338
339    // The Key and KeyId for this testing key provider are created by left
340    // rotating kSecretKey and kKeyId. Note that this implementation is only
341    // intended for testing purpose. The actual key rotation algorithm can be
342    // much more complicated.
343    // Find out the rotating position from |key_id_from_init_data| and apply on
344    // |key|.
345    for (size_t pos = 0; pos < arraysize(kKeyId); ++pos) {
346      std::rotate(key_id->begin(), key_id->begin() + pos, key_id->end());
347      if (*key_id == key_id_from_init_data) {
348        std::rotate(key->begin(), key->begin() + pos, key->end());
349        return true;
350      }
351    }
352    return false;
353  }
354
355  std::vector<uint8> prev_init_data_;
356  uint32 num_distint_need_key_calls_;
357};
358
359// Ignores needkey and does not perform a license request
360class NoResponseApp : public FakeEncryptedMedia::AppBase {
361 public:
362  virtual void OnSessionMessage(const std::string& web_session_id,
363                                const std::vector<uint8>& message,
364                                const GURL& default_url) OVERRIDE {
365    EXPECT_FALSE(web_session_id.empty());
366    EXPECT_FALSE(message.empty());
367    FAIL() << "Unexpected Message";
368  }
369
370  virtual void OnSessionClosed(const std::string& web_session_id) OVERRIDE {
371    EXPECT_FALSE(web_session_id.empty());
372    FAIL() << "Unexpected Closed";
373  }
374
375  virtual void OnSessionKeysChange(const std::string& web_session_id,
376                                   bool has_additional_usable_key) OVERRIDE {
377    EXPECT_FALSE(web_session_id.empty());
378    EXPECT_EQ(has_additional_usable_key, true);
379  }
380
381  virtual void NeedKey(const std::string& type,
382                       const std::vector<uint8>& init_data,
383                       AesDecryptor* decryptor) OVERRIDE {
384  }
385};
386
387// Helper class that emulates calls made on the ChunkDemuxer by the
388// Media Source API.
389class MockMediaSource {
390 public:
391  MockMediaSource(const std::string& filename,
392                  const std::string& mimetype,
393                  int initial_append_size)
394      : file_path_(GetTestDataFilePath(filename)),
395        current_position_(0),
396        initial_append_size_(initial_append_size),
397        mimetype_(mimetype),
398        chunk_demuxer_(new ChunkDemuxer(
399            base::Bind(&MockMediaSource::DemuxerOpened, base::Unretained(this)),
400            base::Bind(&MockMediaSource::DemuxerNeedKey,
401                       base::Unretained(this)),
402            LogCB(),
403            true)),
404        owned_chunk_demuxer_(chunk_demuxer_) {
405
406    file_data_ = ReadTestDataFile(filename);
407
408    if (initial_append_size_ == kAppendWholeFile)
409      initial_append_size_ = file_data_->data_size();
410
411    DCHECK_GT(initial_append_size_, 0);
412    DCHECK_LE(initial_append_size_, file_data_->data_size());
413  }
414
415  virtual ~MockMediaSource() {}
416
417  scoped_ptr<Demuxer> GetDemuxer() { return owned_chunk_demuxer_.Pass(); }
418
419  void set_need_key_cb(const Demuxer::NeedKeyCB& need_key_cb) {
420    need_key_cb_ = need_key_cb;
421  }
422
423  void Seek(base::TimeDelta seek_time, int new_position, int seek_append_size) {
424    chunk_demuxer_->StartWaitingForSeek(seek_time);
425
426    chunk_demuxer_->Abort(
427        kSourceId,
428        base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_);
429
430    DCHECK_GE(new_position, 0);
431    DCHECK_LT(new_position, file_data_->data_size());
432    current_position_ = new_position;
433
434    AppendData(seek_append_size);
435  }
436
437  void AppendData(int size) {
438    DCHECK(chunk_demuxer_);
439    DCHECK_LT(current_position_, file_data_->data_size());
440    DCHECK_LE(current_position_ + size, file_data_->data_size());
441
442    chunk_demuxer_->AppendData(
443        kSourceId, file_data_->data() + current_position_, size,
444        base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_,
445        base::Bind(&MockMediaSource::InitSegmentReceived,
446                   base::Unretained(this)));
447    current_position_ += size;
448  }
449
450  void AppendAtTime(base::TimeDelta timestamp_offset,
451                    const uint8* pData,
452                    int size) {
453    CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId));
454    chunk_demuxer_->AppendData(kSourceId, pData, size,
455                               base::TimeDelta(), kInfiniteDuration(),
456                               &timestamp_offset,
457                               base::Bind(&MockMediaSource::InitSegmentReceived,
458                                          base::Unretained(this)));
459    last_timestamp_offset_ = timestamp_offset;
460  }
461
462  void AppendAtTimeWithWindow(base::TimeDelta timestamp_offset,
463                              base::TimeDelta append_window_start,
464                              base::TimeDelta append_window_end,
465                              const uint8* pData,
466                              int size) {
467    CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId));
468    chunk_demuxer_->AppendData(kSourceId,
469                               pData,
470                               size,
471                               append_window_start,
472                               append_window_end,
473                               &timestamp_offset,
474                               base::Bind(&MockMediaSource::InitSegmentReceived,
475                                          base::Unretained(this)));
476    last_timestamp_offset_ = timestamp_offset;
477  }
478
479  void EndOfStream() {
480    chunk_demuxer_->MarkEndOfStream(PIPELINE_OK);
481  }
482
483  void Abort() {
484    if (!chunk_demuxer_)
485      return;
486    chunk_demuxer_->Shutdown();
487    chunk_demuxer_ = NULL;
488  }
489
490  void DemuxerOpened() {
491    base::MessageLoop::current()->PostTask(
492        FROM_HERE, base::Bind(&MockMediaSource::DemuxerOpenedTask,
493                              base::Unretained(this)));
494  }
495
496  void DemuxerOpenedTask() {
497    // This code assumes that |mimetype_| is one of the following forms.
498    // 1. audio/mpeg
499    // 2. video/webm;codec="vorbis,vp8".
500    size_t semicolon = mimetype_.find(";");
501    std::string type = mimetype_;
502    std::vector<std::string> codecs;
503    if (semicolon != std::string::npos) {
504      type = mimetype_.substr(0, semicolon);
505      size_t codecs_param_start = mimetype_.find("codecs=\"", semicolon);
506
507      CHECK_NE(codecs_param_start, std::string::npos);
508
509      codecs_param_start += 8; // Skip over the codecs=".
510
511      size_t codecs_param_end = mimetype_.find("\"", codecs_param_start);
512
513      CHECK_NE(codecs_param_end, std::string::npos);
514
515      std::string codecs_param =
516          mimetype_.substr(codecs_param_start,
517                           codecs_param_end - codecs_param_start);
518      Tokenize(codecs_param, ",", &codecs);
519    }
520
521    CHECK_EQ(chunk_demuxer_->AddId(kSourceId, type, codecs), ChunkDemuxer::kOk);
522
523    AppendData(initial_append_size_);
524  }
525
526  void DemuxerNeedKey(const std::string& type,
527                      const std::vector<uint8>& init_data) {
528    DCHECK(!init_data.empty());
529    CHECK(!need_key_cb_.is_null());
530    need_key_cb_.Run(type, init_data);
531  }
532
533  base::TimeDelta last_timestamp_offset() const {
534    return last_timestamp_offset_;
535  }
536
537  MOCK_METHOD0(InitSegmentReceived, void(void));
538
539 private:
540  base::FilePath file_path_;
541  scoped_refptr<DecoderBuffer> file_data_;
542  int current_position_;
543  int initial_append_size_;
544  std::string mimetype_;
545  ChunkDemuxer* chunk_demuxer_;
546  scoped_ptr<Demuxer> owned_chunk_demuxer_;
547  Demuxer::NeedKeyCB need_key_cb_;
548  base::TimeDelta last_timestamp_offset_;
549};
550
551class PipelineIntegrationTest
552    : public testing::Test,
553      public PipelineIntegrationTestBase {
554 public:
555  void StartPipelineWithMediaSource(MockMediaSource* source) {
556    EXPECT_CALL(*source, InitSegmentReceived()).Times(AtLeast(1));
557    EXPECT_CALL(*this, OnMetadata(_))
558        .Times(AtMost(1))
559        .WillRepeatedly(SaveArg<0>(&metadata_));
560    EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
561        .Times(AtMost(1));
562    demuxer_ = source->GetDemuxer().Pass();
563    pipeline_->Start(
564        demuxer_.get(),
565        CreateRenderer(NULL),
566        base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)),
567        base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)),
568        QuitOnStatusCB(PIPELINE_OK),
569        base::Bind(&PipelineIntegrationTest::OnMetadata,
570                   base::Unretained(this)),
571        base::Bind(&PipelineIntegrationTest::OnBufferingStateChanged,
572                   base::Unretained(this)),
573        base::Closure(),
574        base::Bind(&PipelineIntegrationTest::OnAddTextTrack,
575                   base::Unretained(this)));
576    message_loop_.Run();
577  }
578
579  void StartHashedPipelineWithMediaSource(MockMediaSource* source) {
580    hashing_enabled_ = true;
581    StartPipelineWithMediaSource(source);
582  }
583
584  void StartPipelineWithEncryptedMedia(
585      MockMediaSource* source,
586      FakeEncryptedMedia* encrypted_media) {
587    EXPECT_CALL(*source, InitSegmentReceived()).Times(AtLeast(1));
588    EXPECT_CALL(*this, OnMetadata(_))
589        .Times(AtMost(1))
590        .WillRepeatedly(SaveArg<0>(&metadata_));
591    EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
592        .Times(AtMost(1));
593    demuxer_ = source->GetDemuxer().Pass();
594    pipeline_->Start(
595        demuxer_.get(),
596        CreateRenderer(encrypted_media->decryptor()),
597        base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)),
598        base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)),
599        QuitOnStatusCB(PIPELINE_OK),
600        base::Bind(&PipelineIntegrationTest::OnMetadata,
601                   base::Unretained(this)),
602        base::Bind(&PipelineIntegrationTest::OnBufferingStateChanged,
603                   base::Unretained(this)),
604        base::Closure(),
605        base::Bind(&PipelineIntegrationTest::OnAddTextTrack,
606                   base::Unretained(this)));
607
608    source->set_need_key_cb(base::Bind(&FakeEncryptedMedia::NeedKey,
609                                       base::Unretained(encrypted_media)));
610
611    message_loop_.Run();
612  }
613
614  // Verifies that seeking works properly for ChunkDemuxer when the
615  // seek happens while there is a pending read on the ChunkDemuxer
616  // and no data is available.
617  bool TestSeekDuringRead(const std::string& filename,
618                          const std::string& mimetype,
619                          int initial_append_size,
620                          base::TimeDelta start_seek_time,
621                          base::TimeDelta seek_time,
622                          int seek_file_position,
623                          int seek_append_size) {
624    MockMediaSource source(filename, mimetype, initial_append_size);
625    StartPipelineWithMediaSource(&source);
626
627    if (pipeline_status_ != PIPELINE_OK)
628      return false;
629
630    Play();
631    if (!WaitUntilCurrentTimeIsAfter(start_seek_time))
632      return false;
633
634    source.Seek(seek_time, seek_file_position, seek_append_size);
635    if (!Seek(seek_time))
636      return false;
637
638    source.EndOfStream();
639
640    source.Abort();
641    Stop();
642    return true;
643  }
644};
645
646TEST_F(PipelineIntegrationTest, BasicPlayback) {
647  ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK));
648
649  Play();
650
651  ASSERT_TRUE(WaitUntilOnEnded());
652}
653
654TEST_F(PipelineIntegrationTest, BasicPlaybackOpusOgg) {
655  ASSERT_TRUE(Start(GetTestDataFilePath("bear-opus.ogg"), PIPELINE_OK));
656
657  Play();
658
659  ASSERT_TRUE(WaitUntilOnEnded());
660}
661
662TEST_F(PipelineIntegrationTest, BasicPlaybackHashed) {
663  ASSERT_TRUE(Start(
664      GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK, kHashed));
665
666  Play();
667
668  ASSERT_TRUE(WaitUntilOnEnded());
669
670  EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
671  EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash());
672  EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());
673}
674
675TEST_F(PipelineIntegrationTest, BasicPlaybackLive) {
676  ASSERT_TRUE(Start(
677      GetTestDataFilePath("bear-320x240-live.webm"), PIPELINE_OK, kHashed));
678
679  Play();
680
681  ASSERT_TRUE(WaitUntilOnEnded());
682
683  EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
684  EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash());
685
686  // TODO: Fix FFmpeg code to return higher resolution time values so
687  // we don't have to truncate our expectations here.
688  EXPECT_EQ(TruncateToFFmpegTimeResolution(kLiveTimelineOffset()),
689            demuxer_->GetTimelineOffset());
690}
691
692TEST_F(PipelineIntegrationTest, F32PlaybackHashed) {
693  ASSERT_TRUE(
694      Start(GetTestDataFilePath("sfx_f32le.wav"), PIPELINE_OK, kHashed));
695  Play();
696  ASSERT_TRUE(WaitUntilOnEnded());
697  EXPECT_EQ(std::string(kNullVideoHash), GetVideoHash());
698  EXPECT_EQ("3.03,2.86,2.99,3.31,3.57,4.06,", GetAudioHash());
699}
700
701TEST_F(PipelineIntegrationTest, BasicPlaybackEncrypted) {
702  FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
703  set_need_key_cb(base::Bind(&FakeEncryptedMedia::NeedKey,
704                             base::Unretained(&encrypted_media)));
705
706  ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-av_enc-av.webm"),
707                    encrypted_media.decryptor()));
708
709  Play();
710
711  ASSERT_TRUE(WaitUntilOnEnded());
712  Stop();
713}
714
715TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource) {
716  MockMediaSource source("bear-320x240.webm", kWebM, 219229);
717  StartPipelineWithMediaSource(&source);
718  source.EndOfStream();
719
720  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
721  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
722  EXPECT_EQ(k320WebMFileDurationMs,
723            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
724
725  Play();
726
727  ASSERT_TRUE(WaitUntilOnEnded());
728
729  EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());
730  source.Abort();
731  Stop();
732}
733
734TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_Live) {
735  MockMediaSource source("bear-320x240-live.webm", kWebM, 219221);
736  StartPipelineWithMediaSource(&source);
737  source.EndOfStream();
738
739  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
740  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
741  EXPECT_EQ(k320WebMFileDurationMs,
742            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
743
744  Play();
745
746  ASSERT_TRUE(WaitUntilOnEnded());
747
748  EXPECT_EQ(kLiveTimelineOffset(),
749            demuxer_->GetTimelineOffset());
750  source.Abort();
751  Stop();
752}
753
754TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_VP9_WebM) {
755  MockMediaSource source("bear-vp9.webm", kWebMVP9, 67504);
756  StartPipelineWithMediaSource(&source);
757  source.EndOfStream();
758
759  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
760  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
761  EXPECT_EQ(kVP9WebMFileDurationMs,
762            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
763
764  Play();
765
766  ASSERT_TRUE(WaitUntilOnEnded());
767  source.Abort();
768  Stop();
769}
770
771TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_VP8A_WebM) {
772  MockMediaSource source("bear-vp8a.webm", kVideoOnlyWebM, kAppendWholeFile);
773  StartPipelineWithMediaSource(&source);
774  source.EndOfStream();
775
776  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
777  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
778  EXPECT_EQ(kVP8AWebMFileDurationMs,
779            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
780
781  Play();
782
783  ASSERT_TRUE(WaitUntilOnEnded());
784  source.Abort();
785  Stop();
786}
787
788TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_Opus_WebM) {
789  MockMediaSource source("bear-opus-end-trimming.webm", kOpusAudioOnlyWebM,
790                         kAppendWholeFile);
791  StartPipelineWithMediaSource(&source);
792  source.EndOfStream();
793
794  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
795  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
796  EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs,
797            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
798  Play();
799
800  ASSERT_TRUE(WaitUntilOnEnded());
801  source.Abort();
802  Stop();
803}
804
805// Flaky. http://crbug.com/304776
806TEST_F(PipelineIntegrationTest, DISABLED_MediaSource_Opus_Seeking_WebM) {
807  MockMediaSource source("bear-opus-end-trimming.webm", kOpusAudioOnlyWebM,
808                         kAppendWholeFile);
809  StartHashedPipelineWithMediaSource(&source);
810
811  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
812  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
813  EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs,
814            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
815
816  base::TimeDelta start_seek_time = base::TimeDelta::FromMilliseconds(1000);
817  base::TimeDelta seek_time = base::TimeDelta::FromMilliseconds(2000);
818
819  Play();
820  ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));
821  source.Seek(seek_time, 0x1D5, 34017);
822  source.EndOfStream();
823  ASSERT_TRUE(Seek(seek_time));
824
825  ASSERT_TRUE(WaitUntilOnEnded());
826
827  EXPECT_EQ("0.76,0.20,-0.82,-0.58,-1.29,-0.29,", GetAudioHash());
828
829  source.Abort();
830  Stop();
831}
832
833TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_WebM) {
834  MockMediaSource source("bear-320x240-16x9-aspect.webm", kWebM,
835                         kAppendWholeFile);
836  StartPipelineWithMediaSource(&source);
837
838  scoped_refptr<DecoderBuffer> second_file =
839      ReadTestDataFile("bear-640x360.webm");
840
841  source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
842                      second_file->data(), second_file->data_size());
843
844  source.EndOfStream();
845
846  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
847  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
848  EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,
849            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
850
851  Play();
852
853  EXPECT_TRUE(WaitUntilOnEnded());
854  source.Abort();
855  Stop();
856}
857
858TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_Encrypted_WebM) {
859  MockMediaSource source("bear-320x240-16x9-aspect-av_enc-av.webm", kWebM,
860                         kAppendWholeFile);
861  FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
862  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
863
864  scoped_refptr<DecoderBuffer> second_file =
865      ReadTestDataFile("bear-640x360-av_enc-av.webm");
866
867  source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
868                      second_file->data(), second_file->data_size());
869
870  source.EndOfStream();
871
872  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
873  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
874  EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,
875            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
876
877  Play();
878
879  EXPECT_TRUE(WaitUntilOnEnded());
880  source.Abort();
881  Stop();
882}
883
884// Config changes from encrypted to clear are not currently supported.
885TEST_F(PipelineIntegrationTest,
886       MediaSource_ConfigChange_ClearThenEncrypted_WebM) {
887  MockMediaSource source("bear-320x240-16x9-aspect.webm", kWebM,
888                         kAppendWholeFile);
889  FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
890  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
891
892  scoped_refptr<DecoderBuffer> second_file =
893      ReadTestDataFile("bear-640x360-av_enc-av.webm");
894
895  source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
896                      second_file->data(), second_file->data_size());
897
898  source.EndOfStream();
899
900  message_loop_.Run();
901  EXPECT_EQ(PIPELINE_ERROR_DECODE, pipeline_status_);
902
903  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
904  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
905  // The second video was not added, so its time has not been added.
906  EXPECT_EQ(k320WebMFileDurationMs,
907            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
908
909  Play();
910
911  EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
912  source.Abort();
913}
914
915// Config changes from clear to encrypted are not currently supported.
916TEST_F(PipelineIntegrationTest,
917       MediaSource_ConfigChange_EncryptedThenClear_WebM) {
918  MockMediaSource source("bear-320x240-16x9-aspect-av_enc-av.webm", kWebM,
919                         kAppendWholeFile);
920  FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
921  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
922
923  scoped_refptr<DecoderBuffer> second_file =
924      ReadTestDataFile("bear-640x360.webm");
925
926  source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
927                      second_file->data(), second_file->data_size());
928
929  source.EndOfStream();
930
931  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
932  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
933  // The second video was not added, so its time has not been added.
934  EXPECT_EQ(k320WebMFileDurationMs,
935            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
936
937  Play();
938
939  EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
940  source.Abort();
941}
942
943#if defined(USE_PROPRIETARY_CODECS)
944TEST_F(PipelineIntegrationTest, MediaSource_ADTS) {
945  MockMediaSource source("sfx.adts", kADTS, kAppendWholeFile);
946  StartPipelineWithMediaSource(&source);
947  source.EndOfStream();
948
949  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
950  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
951  EXPECT_EQ(325, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
952
953  Play();
954
955  EXPECT_TRUE(WaitUntilOnEnded());
956}
957
958TEST_F(PipelineIntegrationTest, MediaSource_ADTS_TimestampOffset) {
959  MockMediaSource source("sfx.adts", kADTS, kAppendWholeFile);
960  StartHashedPipelineWithMediaSource(&source);
961  EXPECT_EQ(325, source.last_timestamp_offset().InMilliseconds());
962
963  // Trim off multiple frames off the beginning of the segment which will cause
964  // the first decoded frame to be incorrect if preroll isn't implemented.
965  const base::TimeDelta adts_preroll_duration =
966      base::TimeDelta::FromSecondsD(2.5 * 1024 / 44100);
967  const base::TimeDelta append_time =
968      source.last_timestamp_offset() - adts_preroll_duration;
969
970  scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile("sfx.adts");
971  source.AppendAtTimeWithWindow(append_time,
972                                append_time + adts_preroll_duration,
973                                kInfiniteDuration(),
974                                second_file->data(),
975                                second_file->data_size());
976  source.EndOfStream();
977
978  EXPECT_EQ(592, source.last_timestamp_offset().InMilliseconds());
979  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
980  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
981  EXPECT_EQ(592, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
982
983  Play();
984
985  EXPECT_TRUE(WaitUntilOnEnded());
986
987  // Verify preroll is stripped.
988  EXPECT_EQ("-0.06,0.97,-0.90,-0.70,-0.53,-0.34,", GetAudioHash());
989}
990
991TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_MP3) {
992  ASSERT_TRUE(Start(GetTestDataFilePath("sfx.mp3"), PIPELINE_OK, kHashed));
993
994  Play();
995
996  ASSERT_TRUE(WaitUntilOnEnded());
997
998  // Verify codec delay and preroll are stripped.
999  EXPECT_EQ("3.05,2.87,3.00,3.32,3.58,4.08,", GetAudioHash());
1000}
1001
1002TEST_F(PipelineIntegrationTest, MediaSource_MP3) {
1003  MockMediaSource source("sfx.mp3", kMP3, kAppendWholeFile);
1004  StartHashedPipelineWithMediaSource(&source);
1005  source.EndOfStream();
1006
1007  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1008  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1009  EXPECT_EQ(313, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1010
1011  Play();
1012
1013  EXPECT_TRUE(WaitUntilOnEnded());
1014
1015  // Verify that codec delay was stripped.
1016  EXPECT_EQ("1.01,2.71,4.18,4.32,3.04,1.12,", GetAudioHash());
1017}
1018
1019TEST_F(PipelineIntegrationTest, MediaSource_MP3_TimestampOffset) {
1020  MockMediaSource source("sfx.mp3", kMP3, kAppendWholeFile);
1021  StartPipelineWithMediaSource(&source);
1022  EXPECT_EQ(313, source.last_timestamp_offset().InMilliseconds());
1023
1024  // There are 576 silent frames at the start of this mp3.  The second append
1025  // should trim them off.
1026  const base::TimeDelta mp3_preroll_duration =
1027      base::TimeDelta::FromSecondsD(576.0 / 44100);
1028  const base::TimeDelta append_time =
1029      source.last_timestamp_offset() - mp3_preroll_duration;
1030
1031  scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile("sfx.mp3");
1032  source.AppendAtTimeWithWindow(append_time,
1033                                append_time + mp3_preroll_duration,
1034                                kInfiniteDuration(),
1035                                second_file->data(),
1036                                second_file->data_size());
1037  source.EndOfStream();
1038
1039  EXPECT_EQ(613, source.last_timestamp_offset().InMilliseconds());
1040  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1041  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1042  EXPECT_EQ(613, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1043
1044  Play();
1045
1046  EXPECT_TRUE(WaitUntilOnEnded());
1047}
1048
1049TEST_F(PipelineIntegrationTest, MediaSource_MP3_Icecast) {
1050  MockMediaSource source("icy_sfx.mp3", kMP3, kAppendWholeFile);
1051  StartPipelineWithMediaSource(&source);
1052  source.EndOfStream();
1053
1054  Play();
1055
1056  EXPECT_TRUE(WaitUntilOnEnded());
1057}
1058
1059TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_MP4) {
1060  MockMediaSource source("bear-640x360-av_frag.mp4", kMP4, kAppendWholeFile);
1061  StartPipelineWithMediaSource(&source);
1062
1063  scoped_refptr<DecoderBuffer> second_file =
1064      ReadTestDataFile("bear-1280x720-av_frag.mp4");
1065
1066  source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1067                      second_file->data(), second_file->data_size());
1068
1069  source.EndOfStream();
1070
1071  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1072  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1073  EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,
1074            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1075
1076  Play();
1077
1078  EXPECT_TRUE(WaitUntilOnEnded());
1079  source.Abort();
1080  Stop();
1081}
1082
1083TEST_F(PipelineIntegrationTest,
1084       MediaSource_ConfigChange_Encrypted_MP4_CENC_VideoOnly) {
1085  MockMediaSource source("bear-640x360-v_frag-cenc.mp4", kMP4Video,
1086                         kAppendWholeFile);
1087  FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1088  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1089
1090  scoped_refptr<DecoderBuffer> second_file =
1091      ReadTestDataFile("bear-1280x720-v_frag-cenc.mp4");
1092
1093  source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1094                      second_file->data(), second_file->data_size());
1095
1096  source.EndOfStream();
1097
1098  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1099  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1100  EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,
1101            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1102
1103  Play();
1104
1105  EXPECT_TRUE(WaitUntilOnEnded());
1106  source.Abort();
1107  Stop();
1108}
1109
1110TEST_F(PipelineIntegrationTest,
1111       MediaSource_ConfigChange_Encrypted_MP4_CENC_KeyRotation_VideoOnly) {
1112  MockMediaSource source("bear-640x360-v_frag-cenc-key_rotation.mp4", kMP4Video,
1113                         kAppendWholeFile);
1114  FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());
1115  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1116
1117  scoped_refptr<DecoderBuffer> second_file =
1118      ReadTestDataFile("bear-1280x720-v_frag-cenc-key_rotation.mp4");
1119
1120  source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1121                      second_file->data(), second_file->data_size());
1122
1123  source.EndOfStream();
1124
1125  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1126  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1127  EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,
1128            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1129
1130  Play();
1131
1132  EXPECT_TRUE(WaitUntilOnEnded());
1133  source.Abort();
1134  Stop();
1135}
1136
1137// Config changes from clear to encrypted are not currently supported.
1138// TODO(ddorwin): Figure out why this CHECKs in AppendAtTime().
1139TEST_F(PipelineIntegrationTest,
1140       DISABLED_MediaSource_ConfigChange_ClearThenEncrypted_MP4_CENC) {
1141  MockMediaSource source("bear-640x360-av_frag.mp4", kMP4Video,
1142                         kAppendWholeFile);
1143  FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1144  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1145
1146  scoped_refptr<DecoderBuffer> second_file =
1147      ReadTestDataFile("bear-1280x720-v_frag-cenc.mp4");
1148
1149  source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1150                      second_file->data(), second_file->data_size());
1151
1152  source.EndOfStream();
1153
1154  message_loop_.Run();
1155  EXPECT_EQ(PIPELINE_ERROR_DECODE, pipeline_status_);
1156
1157  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1158  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1159  // The second video was not added, so its time has not been added.
1160  EXPECT_EQ(k640IsoFileDurationMs,
1161            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1162
1163  Play();
1164
1165  EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
1166  source.Abort();
1167}
1168
1169// Config changes from encrypted to clear are not currently supported.
1170TEST_F(PipelineIntegrationTest,
1171       MediaSource_ConfigChange_EncryptedThenClear_MP4_CENC) {
1172  MockMediaSource source("bear-640x360-v_frag-cenc.mp4", kMP4Video,
1173                         kAppendWholeFile);
1174  FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1175  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1176
1177  scoped_refptr<DecoderBuffer> second_file =
1178      ReadTestDataFile("bear-1280x720-av_frag.mp4");
1179
1180  source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1181                      second_file->data(), second_file->data_size());
1182
1183  source.EndOfStream();
1184
1185  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1186  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1187  // The second video was not added, so its time has not been added.
1188  EXPECT_EQ(k640IsoCencFileDurationMs,
1189            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1190
1191  Play();
1192
1193  EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
1194  source.Abort();
1195}
1196
1197// Verify files which change configuration midstream fail gracefully.
1198TEST_F(PipelineIntegrationTest, MidStreamConfigChangesFail) {
1199  ASSERT_TRUE(Start(
1200      GetTestDataFilePath("midstream_config_change.mp3"), PIPELINE_OK));
1201  Play();
1202  ASSERT_EQ(WaitUntilEndedOrError(), PIPELINE_ERROR_DECODE);
1203}
1204
1205#endif
1206
1207TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) {
1208  ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-16x9-aspect.webm"),
1209                    PIPELINE_OK));
1210  Play();
1211  ASSERT_TRUE(WaitUntilOnEnded());
1212}
1213
1214TEST_F(PipelineIntegrationTest, EncryptedPlayback_WebM) {
1215  MockMediaSource source("bear-320x240-av_enc-av.webm", kWebM, 219816);
1216  FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1217  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1218
1219  source.EndOfStream();
1220  ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1221
1222  Play();
1223
1224  ASSERT_TRUE(WaitUntilOnEnded());
1225  source.Abort();
1226  Stop();
1227}
1228
1229TEST_F(PipelineIntegrationTest, EncryptedPlayback_ClearStart_WebM) {
1230  MockMediaSource source("bear-320x240-av_enc-av_clear-1s.webm", kWebM,
1231                         kAppendWholeFile);
1232  FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1233  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1234
1235  source.EndOfStream();
1236  ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1237
1238  Play();
1239
1240  ASSERT_TRUE(WaitUntilOnEnded());
1241  source.Abort();
1242  Stop();
1243}
1244
1245TEST_F(PipelineIntegrationTest, EncryptedPlayback_NoEncryptedFrames_WebM) {
1246  MockMediaSource source("bear-320x240-av_enc-av_clear-all.webm", kWebM,
1247                         kAppendWholeFile);
1248  FakeEncryptedMedia encrypted_media(new NoResponseApp());
1249  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1250
1251  source.EndOfStream();
1252  ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1253
1254  Play();
1255
1256  ASSERT_TRUE(WaitUntilOnEnded());
1257  source.Abort();
1258  Stop();
1259}
1260
1261#if defined(USE_PROPRIETARY_CODECS)
1262TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_VideoOnly) {
1263  MockMediaSource source("bear-1280x720-v_frag-cenc.mp4", kMP4Video,
1264                         kAppendWholeFile);
1265  FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1266  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1267
1268  source.EndOfStream();
1269  ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1270
1271  Play();
1272
1273  ASSERT_TRUE(WaitUntilOnEnded());
1274  source.Abort();
1275  Stop();
1276}
1277
1278TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_AudioOnly) {
1279  MockMediaSource source("bear-1280x720-a_frag-cenc.mp4", kMP4Audio,
1280                         kAppendWholeFile);
1281  FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1282  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1283
1284  source.EndOfStream();
1285  ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1286
1287  Play();
1288
1289  ASSERT_TRUE(WaitUntilOnEnded());
1290  source.Abort();
1291  Stop();
1292}
1293
1294TEST_F(PipelineIntegrationTest,
1295       EncryptedPlayback_NoEncryptedFrames_MP4_CENC_VideoOnly) {
1296  MockMediaSource source("bear-1280x720-v_frag-cenc_clear-all.mp4", kMP4Video,
1297                         kAppendWholeFile);
1298  FakeEncryptedMedia encrypted_media(new NoResponseApp());
1299  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1300
1301  source.EndOfStream();
1302  ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1303
1304  Play();
1305
1306  ASSERT_TRUE(WaitUntilOnEnded());
1307  source.Abort();
1308  Stop();
1309}
1310
1311TEST_F(PipelineIntegrationTest,
1312       EncryptedPlayback_NoEncryptedFrames_MP4_CENC_AudioOnly) {
1313  MockMediaSource source("bear-1280x720-a_frag-cenc_clear-all.mp4", kMP4Audio,
1314                         kAppendWholeFile);
1315  FakeEncryptedMedia encrypted_media(new NoResponseApp());
1316  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1317
1318  source.EndOfStream();
1319  ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1320
1321  Play();
1322
1323  ASSERT_TRUE(WaitUntilOnEnded());
1324  source.Abort();
1325  Stop();
1326}
1327
1328TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_VideoOnly_MP4_AVC3) {
1329  MockMediaSource source("bear-1280x720-v_frag-avc3.mp4", kMP4VideoAVC3,
1330                         kAppendWholeFile);
1331  StartPipelineWithMediaSource(&source);
1332  source.EndOfStream();
1333
1334  EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1335  EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1336  EXPECT_EQ(k1280IsoAVC3FileDurationMs,
1337            pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1338
1339  Play();
1340
1341  ASSERT_TRUE(WaitUntilOnEnded());
1342  source.Abort();
1343  Stop();
1344}
1345
1346TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_KeyRotation_Video) {
1347  MockMediaSource source("bear-1280x720-v_frag-cenc-key_rotation.mp4",
1348                         kMP4Video, kAppendWholeFile);
1349  FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());
1350  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1351
1352  source.EndOfStream();
1353  ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1354
1355  Play();
1356
1357  ASSERT_TRUE(WaitUntilOnEnded());
1358  source.Abort();
1359  Stop();
1360}
1361
1362TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_KeyRotation_Audio) {
1363  MockMediaSource source("bear-1280x720-a_frag-cenc-key_rotation.mp4",
1364                         kMP4Audio, kAppendWholeFile);
1365  FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());
1366  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1367
1368  source.EndOfStream();
1369  ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1370
1371  Play();
1372
1373  ASSERT_TRUE(WaitUntilOnEnded());
1374  source.Abort();
1375  Stop();
1376}
1377#endif
1378
1379// TODO(acolwell): Fix flakiness http://crbug.com/117921
1380TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePaused) {
1381  ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK));
1382
1383  base::TimeDelta duration(pipeline_->GetMediaDuration());
1384  base::TimeDelta start_seek_time(duration / 4);
1385  base::TimeDelta seek_time(duration * 3 / 4);
1386
1387  Play();
1388  ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));
1389  Pause();
1390  ASSERT_TRUE(Seek(seek_time));
1391  EXPECT_EQ(pipeline_->GetMediaTime(), seek_time);
1392  Play();
1393  ASSERT_TRUE(WaitUntilOnEnded());
1394
1395  // Make sure seeking after reaching the end works as expected.
1396  Pause();
1397  ASSERT_TRUE(Seek(seek_time));
1398  EXPECT_EQ(pipeline_->GetMediaTime(), seek_time);
1399  Play();
1400  ASSERT_TRUE(WaitUntilOnEnded());
1401}
1402
1403// TODO(acolwell): Fix flakiness http://crbug.com/117921
1404TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePlaying) {
1405  ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK));
1406
1407  base::TimeDelta duration(pipeline_->GetMediaDuration());
1408  base::TimeDelta start_seek_time(duration / 4);
1409  base::TimeDelta seek_time(duration * 3 / 4);
1410
1411  Play();
1412  ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));
1413  ASSERT_TRUE(Seek(seek_time));
1414  EXPECT_GE(pipeline_->GetMediaTime(), seek_time);
1415  ASSERT_TRUE(WaitUntilOnEnded());
1416
1417  // Make sure seeking after reaching the end works as expected.
1418  ASSERT_TRUE(Seek(seek_time));
1419  EXPECT_GE(pipeline_->GetMediaTime(), seek_time);
1420  ASSERT_TRUE(WaitUntilOnEnded());
1421}
1422
1423#if defined(USE_PROPRIETARY_CODECS)
1424TEST_F(PipelineIntegrationTest, Rotated_Metadata_0) {
1425  ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_0.mp4"), PIPELINE_OK));
1426  ASSERT_EQ(VIDEO_ROTATION_0, metadata_.video_rotation);
1427}
1428
1429TEST_F(PipelineIntegrationTest, Rotated_Metadata_90) {
1430  ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_90.mp4"), PIPELINE_OK));
1431  ASSERT_EQ(VIDEO_ROTATION_90, metadata_.video_rotation);
1432}
1433
1434TEST_F(PipelineIntegrationTest, Rotated_Metadata_180) {
1435  ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_180.mp4"), PIPELINE_OK));
1436  ASSERT_EQ(VIDEO_ROTATION_180, metadata_.video_rotation);
1437}
1438
1439TEST_F(PipelineIntegrationTest, Rotated_Metadata_270) {
1440  ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_270.mp4"), PIPELINE_OK));
1441  ASSERT_EQ(VIDEO_ROTATION_270, metadata_.video_rotation);
1442}
1443#endif
1444
1445// Verify audio decoder & renderer can handle aborted demuxer reads.
1446TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) {
1447  ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", kAudioOnlyWebM,
1448                                 8192,
1449                                 base::TimeDelta::FromMilliseconds(464),
1450                                 base::TimeDelta::FromMilliseconds(617),
1451                                 0x10CA, 19730));
1452}
1453
1454// Verify video decoder & renderer can handle aborted demuxer reads.
1455TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) {
1456  ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM,
1457                                 32768,
1458                                 base::TimeDelta::FromMilliseconds(167),
1459                                 base::TimeDelta::FromMilliseconds(1668),
1460                                 0x1C896, 65536));
1461}
1462
1463// Verify that Opus audio in WebM containers can be played back.
1464TEST_F(PipelineIntegrationTest, BasicPlayback_AudioOnly_Opus_WebM) {
1465  ASSERT_TRUE(Start(GetTestDataFilePath("bear-opus-end-trimming.webm"),
1466                    PIPELINE_OK));
1467  Play();
1468  ASSERT_TRUE(WaitUntilOnEnded());
1469}
1470
1471// Verify that VP9 video in WebM containers can be played back.
1472TEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_VP9_WebM) {
1473  ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9.webm"),
1474                    PIPELINE_OK));
1475  Play();
1476  ASSERT_TRUE(WaitUntilOnEnded());
1477}
1478
1479// Verify that VP9 video and Opus audio in the same WebM container can be played
1480// back.
1481TEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Opus_WebM) {
1482  ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9-opus.webm"),
1483                    PIPELINE_OK));
1484  Play();
1485  ASSERT_TRUE(WaitUntilOnEnded());
1486}
1487
1488// Verify that VP8 video with alpha channel can be played back.
1489TEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_WebM) {
1490  ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a.webm"),
1491                    PIPELINE_OK));
1492  Play();
1493  ASSERT_TRUE(WaitUntilOnEnded());
1494  EXPECT_EQ(last_video_frame_format_, VideoFrame::YV12A);
1495}
1496
1497// Verify that VP8A video with odd width/height can be played back.
1498TEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_Odd_WebM) {
1499  ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a-odd-dimensions.webm"),
1500                    PIPELINE_OK));
1501  Play();
1502  ASSERT_TRUE(WaitUntilOnEnded());
1503  EXPECT_EQ(last_video_frame_format_, VideoFrame::YV12A);
1504}
1505
1506// Verify that VP9 video with odd width/height can be played back.
1507TEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Odd_WebM) {
1508  ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9-odd-dimensions.webm"),
1509                    PIPELINE_OK));
1510  Play();
1511  ASSERT_TRUE(WaitUntilOnEnded());
1512}
1513
1514// Verify that VP8 video with inband text track can be played back.
1515TEST_F(PipelineIntegrationTest, BasicPlayback_VP8_WebVTT_WebM) {
1516  EXPECT_CALL(*this, OnAddTextTrack(_, _));
1517  ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8-webvtt.webm"),
1518                    PIPELINE_OK));
1519  Play();
1520  ASSERT_TRUE(WaitUntilOnEnded());
1521}
1522
1523// Verify that VP9 video with 4:4:4 subsampling can be played back.
1524TEST_F(PipelineIntegrationTest, P444_VP9_WebM) {
1525  ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-P444.webm"),
1526                    PIPELINE_OK));
1527  Play();
1528  ASSERT_TRUE(WaitUntilOnEnded());
1529  EXPECT_EQ(last_video_frame_format_, VideoFrame::YV24);
1530}
1531
1532// Verify that videos with an odd frame size playback successfully.
1533TEST_F(PipelineIntegrationTest, BasicPlayback_OddVideoSize) {
1534  ASSERT_TRUE(Start(GetTestDataFilePath("butterfly-853x480.webm"),
1535                    PIPELINE_OK));
1536  Play();
1537  ASSERT_TRUE(WaitUntilOnEnded());
1538}
1539
1540// Verify that OPUS audio in a webm which reports a 44.1kHz sample rate plays
1541// correctly at 48kHz
1542TEST_F(PipelineIntegrationTest, BasicPlayback_Opus441kHz) {
1543  ASSERT_TRUE(Start(GetTestDataFilePath("sfx-opus-441.webm"), PIPELINE_OK));
1544  Play();
1545  ASSERT_TRUE(WaitUntilOnEnded());
1546  EXPECT_EQ(48000,
1547            demuxer_->GetStream(DemuxerStream::AUDIO)
1548                ->audio_decoder_config()
1549                .samples_per_second());
1550}
1551
1552// Same as above but using MediaSource.
1553TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_Opus441kHz) {
1554  MockMediaSource source(
1555      "sfx-opus-441.webm", kOpusAudioOnlyWebM, kAppendWholeFile);
1556  StartPipelineWithMediaSource(&source);
1557  source.EndOfStream();
1558  Play();
1559  ASSERT_TRUE(WaitUntilOnEnded());
1560  source.Abort();
1561  Stop();
1562  EXPECT_EQ(48000,
1563            demuxer_->GetStream(DemuxerStream::AUDIO)
1564                ->audio_decoder_config()
1565                .samples_per_second());
1566}
1567
1568// Ensures audio-only playback with missing or negative timestamps works.  Tests
1569// the common live-streaming case for chained ogg.  See http://crbug.com/396864.
1570TEST_F(PipelineIntegrationTest, BasicPlaybackChainedOgg) {
1571  ASSERT_TRUE(Start(GetTestDataFilePath("double-sfx.ogg"), PIPELINE_OK));
1572  Play();
1573  ASSERT_TRUE(WaitUntilOnEnded());
1574  ASSERT_EQ(base::TimeDelta(), demuxer_->GetStartTime());
1575}
1576
1577// Ensures audio-video playback with missing or negative timestamps fails softly
1578// instead of crashing.  See http://crbug.com/396864.
1579TEST_F(PipelineIntegrationTest, BasicPlaybackChainedOggVideo) {
1580  ASSERT_TRUE(Start(GetTestDataFilePath("double-bear.ogv"), PIPELINE_OK));
1581  Play();
1582  EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
1583  ASSERT_EQ(base::TimeDelta(), demuxer_->GetStartTime());
1584}
1585
1586// Tests that we signal ended even when audio runs longer than video track.
1587TEST_F(PipelineIntegrationTest, BasicPlaybackAudioLongerThanVideo) {
1588  ASSERT_TRUE(Start(GetTestDataFilePath("bear_audio_longer_than_video.ogv"),
1589                    PIPELINE_OK));
1590  // Audio track is 2000ms. Video track is 1001ms. Duration should be higher
1591  // of the two.
1592  EXPECT_EQ(2000, pipeline_->GetMediaDuration().InMilliseconds());
1593  Play();
1594  ASSERT_TRUE(WaitUntilOnEnded());
1595}
1596
1597// Tests that we signal ended even when audio runs shorter than video track.
1598TEST_F(PipelineIntegrationTest, BasicPlaybackAudioShorterThanVideo) {
1599  ASSERT_TRUE(Start(GetTestDataFilePath("bear_audio_shorter_than_video.ogv"),
1600                    PIPELINE_OK));
1601  // Audio track is 500ms. Video track is 1001ms. Duration should be higher of
1602  // the two.
1603  EXPECT_EQ(1001, pipeline_->GetMediaDuration().InMilliseconds());
1604  Play();
1605  ASSERT_TRUE(WaitUntilOnEnded());
1606}
1607
1608TEST_F(PipelineIntegrationTest, BasicPlaybackPositiveStartTime) {
1609  ASSERT_TRUE(
1610      Start(GetTestDataFilePath("nonzero-start-time.webm"), PIPELINE_OK));
1611  Play();
1612  ASSERT_TRUE(WaitUntilOnEnded());
1613  ASSERT_EQ(base::TimeDelta::FromMicroseconds(396000),
1614            demuxer_->GetStartTime());
1615}
1616
1617}  // namespace media
1618