| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <deque> | 5 #include <deque> |
| 6 | 6 |
| 7 #include "base/singleton.h" | 7 #include "base/singleton.h" |
| 8 #include "base/tuple.h" | 8 #include "base/tuple.h" |
| 9 #include "media/base/filter_host.h" | 9 #include "media/base/filter_host.h" |
| 10 #include "media/base/filters.h" | 10 #include "media/base/filters.h" |
| 11 #include "media/base/mock_ffmpeg.h" |
| 11 #include "media/base/mock_filter_host.h" | 12 #include "media/base/mock_filter_host.h" |
| 12 #include "media/base/mock_media_filters.h" | 13 #include "media/base/mock_media_filters.h" |
| 13 #include "media/base/mock_reader.h" | 14 #include "media/base/mock_reader.h" |
| 14 #include "media/filters/ffmpeg_common.h" | 15 #include "media/filters/ffmpeg_common.h" |
| 15 #include "media/filters/ffmpeg_demuxer.h" | 16 #include "media/filters/ffmpeg_demuxer.h" |
| 16 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
| 17 | 18 |
| 18 namespace { | 19 using ::testing::_; |
| 19 | 20 using ::testing::DoAll; |
| 20 // Simulates a queue of media packets that get "demuxed" when av_read_frame() | 21 using ::testing::InSequence; |
| 21 // is called. It also tracks the number of packets read but not released, | 22 using ::testing::Return; |
| 22 // which lets us test for memory leaks and handling seeks. | 23 using ::testing::SetArgumentPointee; |
| 23 class PacketQueue : public Singleton<PacketQueue> { | |
| 24 public: | |
| 25 bool IsEmpty() { | |
| 26 return packets_.empty(); | |
| 27 } | |
| 28 | |
| 29 void Enqueue(int stream, size_t size, uint8* data) { | |
| 30 packets_.push_back(PacketTuple(stream, size, data)); | |
| 31 } | |
| 32 | |
| 33 void Dequeue(AVPacket* packet) { | |
| 34 CHECK(!packets_.empty()); | |
| 35 memset(packet, 0, sizeof(*packet)); | |
| 36 packet->stream_index = packets_.front().a; | |
| 37 packet->size = packets_.front().b; | |
| 38 packet->data = packets_.front().c; | |
| 39 packet->destruct = &PacketQueue::DestructPacket; | |
| 40 packets_.pop_front(); | |
| 41 | |
| 42 // We now have an outstanding packet which must be freed at some point. | |
| 43 ++outstanding_packets_; | |
| 44 } | |
| 45 | |
| 46 bool WaitForOutstandingPackets(int count) { | |
| 47 const base::TimeDelta kTimedWait = base::TimeDelta::FromMilliseconds(500); | |
| 48 while (outstanding_packets_ != count) { | |
| 49 if (!wait_for_outstanding_packets_.TimedWait(kTimedWait)) { | |
| 50 return false; | |
| 51 } | |
| 52 } | |
| 53 return true; | |
| 54 } | |
| 55 | |
| 56 private: | |
| 57 static void DestructPacket(AVPacket* packet) { | |
| 58 PacketQueue::get()->DestructPacket(); | |
| 59 } | |
| 60 | |
| 61 void DestructPacket() { | |
| 62 --outstanding_packets_; | |
| 63 wait_for_outstanding_packets_.Signal(); | |
| 64 } | |
| 65 | |
| 66 // Only allow Singleton to create and delete PacketQueue. | |
| 67 friend struct DefaultSingletonTraits<PacketQueue>; | |
| 68 | |
| 69 PacketQueue() | |
| 70 : outstanding_packets_(0), | |
| 71 wait_for_outstanding_packets_(false, false) { | |
| 72 } | |
| 73 | |
| 74 ~PacketQueue() { | |
| 75 CHECK(outstanding_packets_ == 0); | |
| 76 } | |
| 77 | |
| 78 // Packet queue for tests to enqueue mock packets, which are dequeued when | |
| 79 // FFmpegDemuxer calls av_read_frame(). | |
| 80 typedef Tuple3<int, size_t, uint8*> PacketTuple; | |
| 81 std::deque<PacketTuple> packets_; | |
| 82 | |
| 83 // Counts the number of packets "allocated" by av_read_frame() and "released" | |
| 84 // by av_free_packet(). This should always be zero after everything is | |
| 85 // cleaned up. | |
| 86 int outstanding_packets_; | |
| 87 | |
| 88 // Tests can wait on this event until a specific number of outstanding packets | |
| 89 // have been reached. Used to ensure other threads release their references | |
| 90 // to objects so we don't get false positive test results when comparing the | |
| 91 // number of outstanding packets. | |
| 92 base::WaitableEvent wait_for_outstanding_packets_; | |
| 93 | |
| 94 DISALLOW_COPY_AND_ASSIGN(PacketQueue); | |
| 95 }; | |
| 96 | |
| 97 } // namespace | |
| 98 | |
| 99 // FFmpeg mocks to remove dependency on having the DLLs present. | |
| 100 extern "C" { | |
| 101 static const size_t kMaxStreams = 3; | |
| 102 static AVFormatContext g_format; | |
| 103 static AVStream g_streams[kMaxStreams]; | |
| 104 static AVCodecContext g_audio_codec; | |
| 105 static AVCodecContext g_video_codec; | |
| 106 static AVCodecContext g_data_codec; | |
| 107 | |
| 108 // FFmpeg return codes for various functions. | |
| 109 static int g_av_open_input_file = 0; | |
| 110 static int g_av_find_stream_info = 0; | |
| 111 static int g_av_read_frame = 0; | |
| 112 static int g_av_seek_frame = 0; | |
| 113 | |
| 114 // Expected values when seeking. | |
| 115 static base::WaitableEvent* g_seek_event = NULL; | |
| 116 static int64_t g_expected_seek_timestamp = 0; | |
| 117 static int g_expected_seek_flags = 0; | |
| 118 | |
| 119 // Counts outstanding packets allocated by av_new_frame(). | |
| 120 static int g_outstanding_packets_av_new_frame = 0; | |
| 121 | |
| 122 int av_open_input_file(AVFormatContext** format, const char* filename, | |
| 123 AVInputFormat* input_format, int buffer_size, | |
| 124 AVFormatParameters* parameters) { | |
| 125 EXPECT_FALSE(input_format) << "AVInputFormat should be NULL."; | |
| 126 EXPECT_FALSE(buffer_size) << "buffer_size should be 0."; | |
| 127 EXPECT_FALSE(parameters) << "AVFormatParameters should be NULL."; | |
| 128 if (g_av_open_input_file < 0) { | |
| 129 *format = NULL; | |
| 130 } else { | |
| 131 *format = &g_format; | |
| 132 } | |
| 133 return g_av_open_input_file; | |
| 134 } | |
| 135 | |
| 136 int av_find_stream_info(AVFormatContext* format) { | |
| 137 EXPECT_EQ(&g_format, format); | |
| 138 return g_av_find_stream_info; | |
| 139 } | |
| 140 | |
| 141 int64 av_rescale_q(int64 a, AVRational bq, AVRational cq) { | |
| 142 int64 num = bq.num * cq.den; | |
| 143 int64 den = cq.num * bq.den; | |
| 144 return a * num / den; | |
| 145 } | |
| 146 | |
| 147 void av_free_packet(AVPacket* packet) { | |
| 148 if (packet->destruct) { | |
| 149 packet->destruct(packet); | |
| 150 packet->data = NULL; | |
| 151 packet->size = 0; | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 void DestructPacket(AVPacket* packet) { | |
| 156 delete [] packet->data; | |
| 157 --g_outstanding_packets_av_new_frame; | |
| 158 } | |
| 159 | |
| 160 int av_new_packet(AVPacket* packet, int size) { | |
| 161 memset(packet, 0, sizeof(*packet)); | |
| 162 packet->data = new uint8[size]; | |
| 163 packet->size = size; | |
| 164 packet->destruct = &DestructPacket; | |
| 165 ++g_outstanding_packets_av_new_frame; | |
| 166 return 0; | |
| 167 } | |
| 168 | |
| 169 void av_free(void* ptr) { | |
| 170 if (ptr) { | |
| 171 EXPECT_EQ(&g_format, ptr); | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 int av_read_frame(AVFormatContext* format, AVPacket* packet) { | |
| 176 EXPECT_EQ(&g_format, format); | |
| 177 if (g_av_read_frame == 0) { | |
| 178 PacketQueue::get()->Dequeue(packet); | |
| 179 } | |
| 180 return g_av_read_frame; | |
| 181 } | |
| 182 | |
| 183 int av_seek_frame(AVFormatContext *format, int stream_index, int64_t timestamp, | |
| 184 int flags) { | |
| 185 EXPECT_EQ(&g_format, format); | |
| 186 EXPECT_EQ(-1, stream_index); // Should always use -1 for default stream. | |
| 187 EXPECT_EQ(g_expected_seek_timestamp, timestamp); | |
| 188 EXPECT_EQ(g_expected_seek_flags, flags); | |
| 189 EXPECT_FALSE(g_seek_event->IsSignaled()); | |
| 190 g_seek_event->Signal(); | |
| 191 return g_av_seek_frame; | |
| 192 } | |
| 193 | |
| 194 } // extern "C" | |
| 195 | 24 |
| 196 namespace media { | 25 namespace media { |
| 197 | 26 |
| 198 // Fixture class to facilitate writing tests. Takes care of setting up the | 27 // Fixture class to facilitate writing tests. Takes care of setting up the |
| 199 // FFmpeg, pipeline and filter host mocks. | 28 // FFmpeg, pipeline and filter host mocks. |
| 200 class FFmpegDemuxerTest : public testing::Test { | 29 class FFmpegDemuxerTest : public testing::Test { |
| 201 protected: | 30 protected: |
| 202 FFmpegDemuxerTest() {} | 31 // These constants refer to the stream ordering inside AVFormatContext. We |
| 203 virtual ~FFmpegDemuxerTest() {} | 32 // simulate media with a data stream, audio stream and video stream. Having |
| 33 // the data stream first forces the audio and video streams to get remapped |
| 34 // from indices {1,2} to {0,1} respectively, which covers an important test |
| 35 // case. |
| 36 enum AVStreamIndex { |
| 37 AV_STREAM_DATA, |
| 38 AV_STREAM_VIDEO, |
| 39 AV_STREAM_AUDIO, |
| 40 AV_STREAM_MAX, |
| 41 }; |
| 204 | 42 |
| 205 virtual void SetUp() { | 43 // These constants refer to the stream ordering inside an initialized |
| 206 InitializeFFmpegMocks(); | 44 // FFmpegDemuxer based on the ordering of the AVStreamIndex constants. |
| 45 enum DemuxerStreamIndex { |
| 46 DS_STREAM_VIDEO, |
| 47 DS_STREAM_AUDIO, |
| 48 DS_STREAM_MAX, |
| 49 }; |
| 207 | 50 |
| 51 static const int kDurations[]; |
| 52 static const int kChannels; |
| 53 static const int kSampleRate; |
| 54 static const int kWidth; |
| 55 static const int kHeight; |
| 56 |
| 57 static const size_t kDataSize; |
| 58 static const uint8 kAudioData[]; |
| 59 static const uint8 kVideoData[]; |
| 60 static const uint8* kNullData; |
| 61 |
| 62 FFmpegDemuxerTest() |
| 63 : wait_for_demuxer_(false, false) { |
| 208 // Create an FFmpegDemuxer. | 64 // Create an FFmpegDemuxer. |
| 209 factory_ = FFmpegDemuxer::CreateFilterFactory(); | 65 factory_ = FFmpegDemuxer::CreateFilterFactory(); |
| 210 MediaFormat media_format; | 66 MediaFormat media_format; |
| 211 media_format.SetAsString(MediaFormat::kMimeType, | 67 media_format.SetAsString(MediaFormat::kMimeType, |
| 212 mime_type::kApplicationOctetStream); | 68 mime_type::kApplicationOctetStream); |
| 213 demuxer_ = factory_->Create<Demuxer>(media_format); | 69 demuxer_ = factory_->Create<FFmpegDemuxer>(media_format); |
| 214 DCHECK(demuxer_); | 70 DCHECK(demuxer_); |
| 215 | 71 |
| 216 // Prepare a filter host and data source for the demuxer. | 72 // Prepare a filter host and data source for the demuxer. |
| 217 pipeline_.reset(new MockPipeline()); | 73 pipeline_.reset(new MockPipeline()); |
| 218 filter_host_.reset(new MockFilterHost<Demuxer>(pipeline_.get(), demuxer_)); | 74 filter_host_.reset(new MockFilterHost<Demuxer>(pipeline_.get(), demuxer_)); |
| 219 old_mocks::MockFilterConfig config; | 75 old_mocks::MockFilterConfig config; |
| 220 data_source_ = new old_mocks::MockDataSource(&config); | 76 data_source_ = new old_mocks::MockDataSource(&config); |
| 77 |
| 78 // Initialize FFmpeg fixtures. |
| 79 memset(&format_context_, 0, sizeof(format_context_)); |
| 80 memset(&streams_, 0, sizeof(streams_)); |
| 81 memset(&codecs_, 0, sizeof(codecs_)); |
| 82 |
| 83 // Initialize AVCodexContext structures. |
| 84 codecs_[AV_STREAM_DATA].codec_type = CODEC_TYPE_DATA; |
| 85 codecs_[AV_STREAM_DATA].codec_id = CODEC_ID_NONE; |
| 86 |
| 87 codecs_[AV_STREAM_VIDEO].codec_type = CODEC_TYPE_VIDEO; |
| 88 codecs_[AV_STREAM_VIDEO].codec_id = CODEC_ID_THEORA; |
| 89 codecs_[AV_STREAM_VIDEO].width = kWidth; |
| 90 codecs_[AV_STREAM_VIDEO].height = kHeight; |
| 91 |
| 92 codecs_[AV_STREAM_AUDIO].codec_type = CODEC_TYPE_AUDIO; |
| 93 codecs_[AV_STREAM_AUDIO].codec_id = CODEC_ID_VORBIS; |
| 94 codecs_[AV_STREAM_AUDIO].channels = kChannels; |
| 95 codecs_[AV_STREAM_AUDIO].sample_rate = kSampleRate; |
| 96 |
| 97 // Initialize AVStream and AVFormatContext structures. We set the time base |
| 98 // of the streams such that duration is reported in microseconds. |
| 99 format_context_.nb_streams = AV_STREAM_MAX; |
| 100 for (size_t i = 0; i < AV_STREAM_MAX; ++i) { |
| 101 format_context_.streams[i] = &streams_[i]; |
| 102 streams_[i].codec = &codecs_[i]; |
| 103 streams_[i].duration = kDurations[i]; |
| 104 streams_[i].time_base.den = 1 * base::Time::kMicrosecondsPerSecond; |
| 105 streams_[i].time_base.num = 1; |
| 106 } |
| 107 |
| 108 // Initialize MockFFmpeg. |
| 109 MockFFmpeg::set(&mock_ffmpeg_); |
| 221 } | 110 } |
| 222 | 111 |
| 223 virtual void TearDown() { | 112 virtual ~FFmpegDemuxerTest() { |
| 224 // Call Stop() to shut down internal threads. | 113 // Call Stop() to shut down internal threads. |
| 225 demuxer_->Stop(); | 114 demuxer_->Stop(); |
| 115 |
| 116 // Reset MockFFmpeg. |
| 117 MockFFmpeg::set(NULL); |
| 118 } |
| 119 |
| 120 // Sets up MockFFmpeg to allow FFmpegDemuxer to successfully initialize. |
| 121 void InitializeDemuxerMocks() { |
| 122 EXPECT_CALL(*MockFFmpeg::get(), AVOpenInputFile(_, _, NULL, 0, NULL)) |
| 123 .WillOnce(DoAll(SetArgumentPointee<0>(&format_context_), Return(0))); |
| 124 EXPECT_CALL(*MockFFmpeg::get(), AVFindStreamInfo(&format_context_)) |
| 125 .WillOnce(Return(0)); |
| 126 EXPECT_CALL(*MockFFmpeg::get(), AVFree(&format_context_)); |
| 127 } |
| 128 |
| 129 // Initializes both MockFFmpeg and FFmpegDemuxer. |
| 130 void InitializeDemuxer() { |
| 131 InitializeDemuxerMocks(); |
| 132 EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); |
| 133 EXPECT_TRUE(filter_host_->WaitForInitialized()); |
| 134 EXPECT_TRUE(filter_host_->IsInitialized()); |
| 135 EXPECT_EQ(PIPELINE_OK, pipeline_->GetError()); |
| 136 } |
| 137 |
| 138 // To eliminate flakiness, this method will wait for the demuxer's message |
| 139 // loop to finish any currently executing and queued tasks. |
| 140 void WaitForDemuxerThread() { |
| 141 demuxer_->thread_.message_loop()->PostTask(FROM_HERE, |
| 142 NewRunnableFunction(&FFmpegDemuxerTest::Notify, &wait_for_demuxer_)); |
| 143 wait_for_demuxer_.Wait(); |
| 226 } | 144 } |
| 227 | 145 |
| 228 // Fixture members. | 146 // Fixture members. |
| 229 scoped_refptr<FilterFactory> factory_; | 147 scoped_refptr<FilterFactory> factory_; |
| 230 scoped_refptr<Demuxer> demuxer_; | 148 scoped_refptr<FFmpegDemuxer> demuxer_; |
| 231 scoped_ptr<MockPipeline> pipeline_; | 149 scoped_ptr<MockPipeline> pipeline_; |
| 232 scoped_ptr<MockFilterHost<Demuxer> > filter_host_; | 150 scoped_ptr<MockFilterHost<Demuxer> > filter_host_; |
| 233 scoped_refptr<old_mocks::MockDataSource> data_source_; | 151 scoped_refptr<old_mocks::MockDataSource> data_source_; |
| 234 | 152 |
| 153 // FFmpeg fixtures. |
| 154 AVFormatContext format_context_; |
| 155 AVCodecContext codecs_[AV_STREAM_MAX]; |
| 156 AVStream streams_[AV_STREAM_MAX]; |
| 157 MockFFmpeg mock_ffmpeg_; |
| 158 |
| 235 private: | 159 private: |
| 236 static void InitializeFFmpegMocks() { | 160 // Used with NewRunnableFunction() -- we don't use NewRunnableMethod() since |
| 237 // Initialize function return codes. | 161 // it would force this class to be refcounted causing double deletions. |
| 238 g_av_open_input_file = 0; | 162 static void Notify(base::WaitableEvent* event) { |
| 239 g_av_find_stream_info = 0; | 163 event->Signal(); |
| 240 g_av_read_frame = 0; | 164 } |
| 241 | 165 |
| 242 // Initialize AVFormatContext structure. | 166 base::WaitableEvent wait_for_demuxer_; |
| 243 memset(&g_format, 0, sizeof(g_format)); | |
| 244 | |
| 245 // Initialize AVStream structures. | |
| 246 for (size_t i = 0; i < kMaxStreams; ++i) { | |
| 247 memset(&g_streams[i], 0, sizeof(g_streams[i])); | |
| 248 g_streams[i].time_base.den = 1 * base::Time::kMicrosecondsPerSecond; | |
| 249 g_streams[i].time_base.num = 1; | |
| 250 } | |
| 251 | |
| 252 // Initialize AVCodexContext structures. | |
| 253 memset(&g_audio_codec, 0, sizeof(g_audio_codec)); | |
| 254 g_audio_codec.codec_type = CODEC_TYPE_AUDIO; | |
| 255 g_audio_codec.codec_id = CODEC_ID_VORBIS; | |
| 256 g_audio_codec.channels = 2; | |
| 257 g_audio_codec.sample_rate = 44100; | |
| 258 | |
| 259 memset(&g_video_codec, 0, sizeof(g_video_codec)); | |
| 260 g_video_codec.codec_type = CODEC_TYPE_VIDEO; | |
| 261 g_video_codec.codec_id = CODEC_ID_THEORA; | |
| 262 g_video_codec.height = 720; | |
| 263 g_video_codec.width = 1280; | |
| 264 | |
| 265 memset(&g_data_codec, 0, sizeof(g_data_codec)); | |
| 266 g_data_codec.codec_type = CODEC_TYPE_DATA; | |
| 267 g_data_codec.codec_id = CODEC_ID_NONE; | |
| 268 } | |
| 269 | 167 |
| 270 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest); | 168 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest); |
| 271 }; | 169 }; |
| 272 | 170 |
| 171 // These durations are picked so that the demuxer chooses the longest supported |
| 172 // stream, which would be 30 in this case for the audio stream. |
| 173 const int FFmpegDemuxerTest::kDurations[AV_STREAM_MAX] = {100, 20, 30}; |
| 174 const int FFmpegDemuxerTest::kChannels = 2; |
| 175 const int FFmpegDemuxerTest::kSampleRate = 44100; |
| 176 const int FFmpegDemuxerTest::kWidth = 1280; |
| 177 const int FFmpegDemuxerTest::kHeight = 720; |
| 178 |
| 179 const size_t FFmpegDemuxerTest::kDataSize = 4; |
| 180 const uint8 FFmpegDemuxerTest::kAudioData[kDataSize] = {0, 1, 2, 3}; |
| 181 const uint8 FFmpegDemuxerTest::kVideoData[kDataSize] = {4, 5, 6, 7}; |
| 182 const uint8* FFmpegDemuxerTest::kNullData = NULL; |
| 183 |
| 273 TEST(FFmpegDemuxerFactoryTest, Create) { | 184 TEST(FFmpegDemuxerFactoryTest, Create) { |
| 274 // Should only accept application/octet-stream type. | 185 // Should only accept application/octet-stream type. |
| 275 scoped_refptr<FilterFactory> factory = FFmpegDemuxer::CreateFilterFactory(); | 186 scoped_refptr<FilterFactory> factory = FFmpegDemuxer::CreateFilterFactory(); |
| 276 MediaFormat media_format; | 187 MediaFormat media_format; |
| 277 media_format.SetAsString(MediaFormat::kMimeType, "foo/x-bar"); | 188 media_format.SetAsString(MediaFormat::kMimeType, "foo/x-bar"); |
| 278 scoped_refptr<Demuxer> demuxer(factory->Create<Demuxer>(media_format)); | 189 scoped_refptr<Demuxer> demuxer(factory->Create<Demuxer>(media_format)); |
| 279 ASSERT_FALSE(demuxer); | 190 ASSERT_FALSE(demuxer); |
| 280 | 191 |
| 281 // Try again with application/octet-stream mime type. | 192 // Try again with application/octet-stream mime type. |
| 282 media_format.Clear(); | 193 media_format.Clear(); |
| 283 media_format.SetAsString(MediaFormat::kMimeType, | 194 media_format.SetAsString(MediaFormat::kMimeType, |
| 284 mime_type::kApplicationOctetStream); | 195 mime_type::kApplicationOctetStream); |
| 285 demuxer = factory->Create<Demuxer>(media_format); | 196 demuxer = factory->Create<Demuxer>(media_format); |
| 286 ASSERT_TRUE(demuxer); | 197 ASSERT_TRUE(demuxer); |
| 287 } | 198 } |
| 288 | 199 |
| 289 TEST_F(FFmpegDemuxerTest, InitializeCouldNotOpen) { | 200 TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) { |
| 290 // Simulate av_open_input_fail failing. | 201 // Simulate av_open_input_file() failing. |
| 291 g_av_open_input_file = AVERROR_IO; | 202 EXPECT_CALL(*MockFFmpeg::get(), AVOpenInputFile(_, _, NULL, 0, NULL)) |
| 292 g_av_find_stream_info = 0; | 203 .WillOnce(Return(-1)); |
| 204 |
| 293 EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); | 205 EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); |
| 294 EXPECT_TRUE(filter_host_->WaitForError(DEMUXER_ERROR_COULD_NOT_OPEN)); | 206 EXPECT_TRUE(filter_host_->WaitForError(DEMUXER_ERROR_COULD_NOT_OPEN)); |
| 295 EXPECT_FALSE(filter_host_->IsInitialized()); | 207 EXPECT_FALSE(filter_host_->IsInitialized()); |
| 296 } | 208 } |
| 297 | 209 |
| 298 TEST_F(FFmpegDemuxerTest, InitializeCouldNotParse) { | 210 TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) { |
| 299 // Simulate av_find_stream_info failing. | 211 // Simulate av_find_stream_info() failing. |
| 300 g_av_open_input_file = 0; | 212 EXPECT_CALL(*MockFFmpeg::get(), AVOpenInputFile(_, _, NULL, 0, NULL)) |
| 301 g_av_find_stream_info = AVERROR_IO; | 213 .WillOnce(DoAll(SetArgumentPointee<0>(&format_context_), Return(0))); |
| 214 EXPECT_CALL(*MockFFmpeg::get(), AVFindStreamInfo(&format_context_)) |
| 215 .WillOnce(Return(AVERROR_IO)); |
| 216 EXPECT_CALL(*MockFFmpeg::get(), AVFree(&format_context_)); |
| 302 | 217 |
| 303 EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); | 218 EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); |
| 304 EXPECT_TRUE(filter_host_->WaitForError(DEMUXER_ERROR_COULD_NOT_PARSE)); | 219 EXPECT_TRUE(filter_host_->WaitForError(DEMUXER_ERROR_COULD_NOT_PARSE)); |
| 305 EXPECT_FALSE(filter_host_->IsInitialized()); | 220 EXPECT_FALSE(filter_host_->IsInitialized()); |
| 306 } | 221 } |
| 307 | 222 |
| 308 TEST_F(FFmpegDemuxerTest, InitializeNoStreams) { | 223 TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) { |
| 309 // Simulate media with no parseable streams. | 224 // Simulate media with no parseable streams. |
| 310 EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); | 225 { |
| 311 EXPECT_TRUE(filter_host_->WaitForError(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); | 226 SCOPED_TRACE(""); |
| 312 EXPECT_FALSE(filter_host_->IsInitialized()); | 227 InitializeDemuxerMocks(); |
| 313 } | 228 } |
| 314 | 229 format_context_.nb_streams = 0; |
| 315 TEST_F(FFmpegDemuxerTest, InitializeDataStreamOnly) { | |
| 316 // Simulate media with a data stream but no audio or video streams. | |
| 317 g_format.nb_streams = 1; | |
| 318 g_format.streams[0] = &g_streams[0]; | |
| 319 g_streams[0].codec = &g_data_codec; | |
| 320 g_streams[0].duration = 10; | |
| 321 | 230 |
| 322 EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); | 231 EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); |
| 323 EXPECT_TRUE(filter_host_->WaitForError(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); | 232 EXPECT_TRUE(filter_host_->WaitForError(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); |
| 324 EXPECT_FALSE(filter_host_->IsInitialized()); | 233 EXPECT_FALSE(filter_host_->IsInitialized()); |
| 325 } | 234 } |
| 326 | 235 |
| 327 TEST_F(FFmpegDemuxerTest, InitializeStreams) { | 236 TEST_F(FFmpegDemuxerTest, Initialize_DataStreamOnly) { |
| 328 // Simulate media with a data stream, a video stream and audio stream. | 237 // Simulate media with a data stream but no audio or video streams. |
| 329 g_format.nb_streams = 3; | 238 { |
| 330 g_format.streams[0] = &g_streams[0]; | 239 SCOPED_TRACE(""); |
| 331 g_format.streams[1] = &g_streams[1]; | 240 InitializeDemuxerMocks(); |
| 332 g_format.streams[2] = &g_streams[2]; | 241 } |
| 333 g_streams[0].duration = 1000; | 242 EXPECT_EQ(format_context_.streams[0], &streams_[AV_STREAM_DATA]); |
| 334 g_streams[0].codec = &g_data_codec; | 243 format_context_.nb_streams = 1; |
| 335 g_streams[1].duration = 100; | |
| 336 g_streams[1].codec = &g_video_codec; | |
| 337 g_streams[2].duration = 10; | |
| 338 g_streams[2].codec = &g_audio_codec; | |
| 339 | 244 |
| 340 // Initialize the demuxer. | |
| 341 EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); | 245 EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); |
| 342 EXPECT_TRUE(filter_host_->WaitForInitialized()); | 246 EXPECT_TRUE(filter_host_->WaitForError(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); |
| 343 EXPECT_TRUE(filter_host_->IsInitialized()); | 247 EXPECT_FALSE(filter_host_->IsInitialized()); |
| 344 EXPECT_EQ(PIPELINE_OK, pipeline_->GetError()); | 248 } |
| 345 | 249 |
| 346 // Since we ignore data streams, the duration should be equal to the video | 250 TEST_F(FFmpegDemuxerTest, Initialize_Successful) { |
| 347 // stream's duration. | 251 { |
| 348 EXPECT_EQ(g_streams[1].duration, pipeline_->GetDuration().InMicroseconds()); | 252 SCOPED_TRACE(""); |
| 253 InitializeDemuxer(); |
| 254 } |
| 349 | 255 |
| 350 // Verify that 2 out of 3 streams were created. | 256 // Verify that our demuxer streams were created from our AVStream structures. |
| 351 EXPECT_EQ(2u, demuxer_->GetNumberOfStreams()); | 257 EXPECT_EQ(DS_STREAM_MAX, static_cast<int>(demuxer_->GetNumberOfStreams())); |
| 352 | 258 |
| 353 // First stream should be video and support FFmpegDemuxerStream interface. | 259 // Since we ignore data streams, the duration should be equal to the longest |
| 354 scoped_refptr<DemuxerStream> stream = demuxer_->GetStream(0); | 260 // supported stream's duration (audio, in this case). |
| 261 EXPECT_EQ(kDurations[AV_STREAM_AUDIO], |
| 262 pipeline_->GetDuration().InMicroseconds()); |
| 263 |
| 264 // First stream should be video and support the FFmpegDemuxerStream interface. |
| 265 scoped_refptr<DemuxerStream> stream = demuxer_->GetStream(DS_STREAM_VIDEO); |
| 355 AVStreamProvider* av_stream_provider = NULL; | 266 AVStreamProvider* av_stream_provider = NULL; |
| 356 ASSERT_TRUE(stream); | 267 ASSERT_TRUE(stream); |
| 357 std::string mime_type; | 268 std::string mime_type; |
| 358 EXPECT_TRUE( | 269 EXPECT_TRUE( |
| 359 stream->media_format().GetAsString(MediaFormat::kMimeType, &mime_type)); | 270 stream->media_format().GetAsString(MediaFormat::kMimeType, &mime_type)); |
| 360 EXPECT_STREQ(mime_type::kFFmpegVideo, mime_type.c_str()); | 271 EXPECT_STREQ(mime_type::kFFmpegVideo, mime_type.c_str()); |
| 361 EXPECT_TRUE(stream->QueryInterface(&av_stream_provider)); | 272 EXPECT_TRUE(stream->QueryInterface(&av_stream_provider)); |
| 362 EXPECT_TRUE(av_stream_provider); | 273 EXPECT_TRUE(av_stream_provider); |
| 363 EXPECT_EQ(&g_streams[1], av_stream_provider->GetAVStream()); | 274 EXPECT_EQ(&streams_[AV_STREAM_VIDEO], av_stream_provider->GetAVStream()); |
| 364 | 275 |
| 365 // Second stream should be audio and support FFmpegDemuxerStream interface. | 276 // Other stream should be audio and support the FFmpegDemuxerStream interface. |
| 366 stream = demuxer_->GetStream(1); | 277 stream = demuxer_->GetStream(DS_STREAM_AUDIO); |
| 367 av_stream_provider = NULL; | 278 av_stream_provider = NULL; |
| 368 ASSERT_TRUE(stream); | 279 ASSERT_TRUE(stream); |
| 369 EXPECT_TRUE(stream->media_format().GetAsString(MediaFormat::kMimeType, | 280 EXPECT_TRUE(stream->media_format().GetAsString(MediaFormat::kMimeType, |
| 370 &mime_type)); | 281 &mime_type)); |
| 371 EXPECT_STREQ(mime_type::kFFmpegAudio, mime_type.c_str()); | 282 EXPECT_STREQ(mime_type::kFFmpegAudio, mime_type.c_str()); |
| 372 EXPECT_TRUE(stream->QueryInterface(&av_stream_provider)); | 283 EXPECT_TRUE(stream->QueryInterface(&av_stream_provider)); |
| 373 EXPECT_TRUE(av_stream_provider); | 284 EXPECT_TRUE(av_stream_provider); |
| 374 EXPECT_EQ(&g_streams[2], av_stream_provider->GetAVStream()); | 285 EXPECT_EQ(&streams_[AV_STREAM_AUDIO], av_stream_provider->GetAVStream()); |
| 375 } | 286 } |
| 376 | 287 |
| 377 TEST_F(FFmpegDemuxerTest, ReadAndSeek) { | 288 TEST_F(FFmpegDemuxerTest, Read) { |
| 378 // Prepare some test data. | 289 // We're testing the following: |
| 379 const int kPacketData = 0; | 290 // |
| 380 const int kPacketAudio = 1; | 291 // 1) The demuxer immediately frees packets it doesn't care about and keeps |
| 381 const int kPacketVideo = 2; | 292 // reading until it finds a packet it cares about. |
| 382 const int kAudio = 0; | 293 // 2) The demuxer doesn't free packets that we read from it. |
| 383 const int kVideo = 1; | 294 // 3) On end of stream, the demuxer queues end of stream packets on every |
| 384 const size_t kDataSize = 4; | 295 // stream. |
| 385 uint8 audio_data[kDataSize] = {0, 1, 2, 3}; | 296 // |
| 386 uint8 video_data[kDataSize] = {4, 5, 6, 7}; | 297 // Since we can't test which packets are being freed, we use check points to |
| 387 | 298 // infer that the correct packets have been freed. |
| 388 // Simulate media with a data stream, audio stream and video stream. Having | 299 { |
| 389 // the data stream first forces the audio and video streams to get remapped | 300 SCOPED_TRACE(""); |
| 390 // from indices {1,2} to {0,1} respectively, which covers an important test | 301 InitializeDemuxer(); |
| 391 // case. | 302 } |
| 392 g_format.nb_streams = 3; | |
| 393 g_format.streams[kPacketData] = &g_streams[0]; | |
| 394 g_format.streams[kPacketAudio] = &g_streams[1]; | |
| 395 g_format.streams[kPacketVideo] = &g_streams[2]; | |
| 396 g_streams[0].duration = 10; | |
| 397 g_streams[0].codec = &g_data_codec; | |
| 398 g_streams[1].duration = 10; | |
| 399 g_streams[1].codec = &g_audio_codec; | |
| 400 g_streams[2].duration = 10; | |
| 401 g_streams[2].codec = &g_video_codec; | |
| 402 | |
| 403 // Initialize the demuxer. | |
| 404 EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); | |
| 405 EXPECT_TRUE(filter_host_->WaitForInitialized()); | |
| 406 EXPECT_TRUE(filter_host_->IsInitialized()); | |
| 407 EXPECT_EQ(PIPELINE_OK, pipeline_->GetError()); | |
| 408 | |
| 409 // Verify both streams were created. | |
| 410 EXPECT_EQ(2u, demuxer_->GetNumberOfStreams()); | |
| 411 | 303 |
| 412 // Get our streams. | 304 // Get our streams. |
| 413 scoped_refptr<DemuxerStream> audio_stream = demuxer_->GetStream(kAudio); | 305 scoped_refptr<DemuxerStream> video = demuxer_->GetStream(DS_STREAM_VIDEO); |
| 414 scoped_refptr<DemuxerStream> video_stream = demuxer_->GetStream(kVideo); | 306 scoped_refptr<DemuxerStream> audio = demuxer_->GetStream(DS_STREAM_AUDIO); |
| 415 ASSERT_TRUE(audio_stream); | 307 ASSERT_TRUE(video); |
| 416 ASSERT_TRUE(video_stream); | 308 ASSERT_TRUE(audio); |
| 417 | 309 |
| 418 // Prepare data packets, which should all get immediately released. | 310 // Expect all calls in sequence. |
| 419 PacketQueue::get()->Enqueue(kPacketData, kDataSize, audio_data); | 311 InSequence s; |
| 420 PacketQueue::get()->Enqueue(kPacketData, kDataSize, audio_data); | 312 |
| 421 PacketQueue::get()->Enqueue(kPacketData, kDataSize, audio_data); | 313 // The demuxer will read a data packet which will get immediately freed, |
| 422 | 314 // followed by reading an audio packet... |
| 423 // Prepare our test audio packet. | 315 EXPECT_CALL(*MockFFmpeg::get(), AVReadFrame(&format_context_, _)) |
| 424 PacketQueue::get()->Enqueue(kPacketAudio, kDataSize, audio_data); | 316 .WillOnce(CreatePacket(AV_STREAM_DATA, kNullData, 0)); |
| 317 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)).WillOnce(FreePacket()); |
| 318 EXPECT_CALL(*MockFFmpeg::get(), AVReadFrame(&format_context_, _)) |
| 319 .WillOnce(CreatePacket(AV_STREAM_AUDIO, kAudioData, kDataSize)); |
| 320 |
| 321 // ...then we'll free it with some sanity checkpoints... |
| 322 EXPECT_CALL(*MockFFmpeg::get(), CheckPoint(1)); |
| 323 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)).WillOnce(FreePacket()); |
| 324 EXPECT_CALL(*MockFFmpeg::get(), CheckPoint(2)); |
| 325 |
| 326 // ...then we'll read a video packet... |
| 327 EXPECT_CALL(*MockFFmpeg::get(), AVReadFrame(&format_context_, _)) |
| 328 .WillOnce(CreatePacket(AV_STREAM_VIDEO, kVideoData, kDataSize)); |
| 329 |
| 330 // ...then we'll free it with some sanity checkpoints... |
| 331 EXPECT_CALL(*MockFFmpeg::get(), CheckPoint(3)); |
| 332 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)).WillOnce(FreePacket()); |
| 333 EXPECT_CALL(*MockFFmpeg::get(), CheckPoint(4)); |
| 334 |
| 335 // ...then we'll simulate end of stream. Note that a packet isn't "created" |
| 336 // in this situation so there is no outstanding packet. However an end of |
| 337 // stream packet is created for each stream, which means av_free_packet() |
| 338 // will still be called twice. |
| 339 EXPECT_CALL(*MockFFmpeg::get(), AVReadFrame(&format_context_, _)) |
| 340 .WillOnce(Return(AVERROR_IO)); |
| 341 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)); |
| 342 EXPECT_CALL(*MockFFmpeg::get(), CheckPoint(5)); |
| 343 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)); |
| 344 EXPECT_CALL(*MockFFmpeg::get(), CheckPoint(6)); |
| 425 | 345 |
| 426 // Attempt a read from the audio stream and run the message loop until done. | 346 // Attempt a read from the audio stream and run the message loop until done. |
| 427 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | 347 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
| 428 reader->Read(audio_stream); | 348 reader->Read(audio); |
| 429 pipeline_->RunAllTasks(); | 349 pipeline_->RunAllTasks(); |
| 430 EXPECT_TRUE(reader->WaitForRead()); | 350 EXPECT_TRUE(reader->WaitForRead()); |
| 431 EXPECT_TRUE(reader->called()); | 351 EXPECT_TRUE(reader->called()); |
| 432 ASSERT_TRUE(reader->buffer()); | 352 ASSERT_TRUE(reader->buffer()); |
| 433 EXPECT_FALSE(reader->buffer()->IsDiscontinuous()); | 353 EXPECT_FALSE(reader->buffer()->IsDiscontinuous()); |
| 434 EXPECT_EQ(audio_data, reader->buffer()->GetData()); | 354 EXPECT_EQ(kAudioData, reader->buffer()->GetData()); |
| 435 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); | 355 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 436 | 356 |
| 437 // Prepare our test video packet. | 357 // We shouldn't have freed the audio packet yet. |
| 438 PacketQueue::get()->Enqueue(kPacketVideo, kDataSize, video_data); | 358 MockFFmpeg::get()->CheckPoint(1); |
| 359 |
| 360 // Manually release the last reference to the buffer. |
| 361 reader->Reset(); |
| 362 WaitForDemuxerThread(); |
| 363 MockFFmpeg::get()->CheckPoint(2); |
| 439 | 364 |
| 440 // Attempt a read from the video stream and run the message loop until done. | 365 // Attempt a read from the video stream and run the message loop until done. |
| 441 reader->Reset(); | 366 reader->Read(video); |
| 442 reader->Read(video_stream); | 367 pipeline_->RunAllTasks(); |
| 443 pipeline_->RunAllTasks(); | 368 EXPECT_TRUE(reader->WaitForRead()); |
| 444 EXPECT_TRUE(reader->WaitForRead()); | 369 EXPECT_TRUE(reader->called()); |
| 445 EXPECT_TRUE(reader->called()); | 370 ASSERT_TRUE(reader->buffer()); |
| 446 ASSERT_TRUE(reader->buffer()); | 371 EXPECT_FALSE(reader->buffer()->IsDiscontinuous()); |
| 447 EXPECT_FALSE(reader->buffer()->IsDiscontinuous()); | 372 EXPECT_EQ(kVideoData, reader->buffer()->GetData()); |
| 448 EXPECT_EQ(video_data, reader->buffer()->GetData()); | 373 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 449 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); | 374 |
| 375 // We shouldn't have freed the video packet yet. |
| 376 MockFFmpeg::get()->CheckPoint(3); |
| 377 |
| 378 // Manually release the last reference to the buffer and verify it was freed. |
| 379 reader->Reset(); |
| 380 WaitForDemuxerThread(); |
| 381 MockFFmpeg::get()->CheckPoint(4); |
| 382 |
| 383 // We should now expect an end of stream buffer in both the audio and video |
| 384 // streams. |
| 385 |
| 386 // Attempt a read from the audio stream and run the message loop until done. |
| 387 reader->Read(audio); |
| 388 pipeline_->RunAllTasks(); |
| 389 EXPECT_TRUE(reader->WaitForRead()); |
| 390 EXPECT_TRUE(reader->called()); |
| 391 ASSERT_TRUE(reader->buffer()); |
| 392 EXPECT_TRUE(reader->buffer()->IsEndOfStream()); |
| 393 EXPECT_EQ(NULL, reader->buffer()->GetData()); |
| 394 EXPECT_EQ(0u, reader->buffer()->GetDataSize()); |
| 450 | 395 |
| 451 // Manually release buffer, which should release any remaining AVPackets. | 396 // Manually release buffer, which should release any remaining AVPackets. |
| 452 reader = NULL; | 397 reader->Reset(); |
| 453 EXPECT_TRUE(PacketQueue::get()->WaitForOutstandingPackets(0)); | 398 WaitForDemuxerThread(); |
| 454 | 399 MockFFmpeg::get()->CheckPoint(5); |
| 455 //---------------------------------------------------------------------------- | 400 |
| 456 // Seek tests. | 401 // Attempt a read from the audio stream and run the message loop until done. |
| 457 EXPECT_FALSE(g_seek_event); | 402 reader->Read(video); |
| 458 g_seek_event = new base::WaitableEvent(false, false); | 403 pipeline_->RunAllTasks(); |
| 459 | 404 EXPECT_TRUE(reader->WaitForRead()); |
| 460 // Let's trigger a simple forward seek with no outstanding packets. | 405 EXPECT_TRUE(reader->called()); |
| 461 g_expected_seek_timestamp = 1234; | 406 ASSERT_TRUE(reader->buffer()); |
| 462 g_expected_seek_flags = 0; | 407 EXPECT_TRUE(reader->buffer()->IsEndOfStream()); |
| 463 demuxer_->Seek(base::TimeDelta::FromMicroseconds(g_expected_seek_timestamp)); | 408 EXPECT_EQ(NULL, reader->buffer()->GetData()); |
| 464 EXPECT_TRUE(g_seek_event->TimedWait(base::TimeDelta::FromSeconds(1))); | 409 EXPECT_EQ(0u, reader->buffer()->GetDataSize()); |
| 410 |
| 411 // Manually release buffer, which should release any remaining AVPackets. |
| 412 reader->Reset(); |
| 413 WaitForDemuxerThread(); |
| 414 MockFFmpeg::get()->CheckPoint(6); |
| 415 } |
| 416 |
| 417 TEST_F(FFmpegDemuxerTest, Seek) { |
| 418 // We're testing the following: |
| 419 // |
| 420 // 1) The demuxer frees all queued packets when it receives a Seek(). |
| 421 // 2) The demuxer queues a single discontinuous packet on every stream. |
| 422 // |
| 423 // Since we can't test which packets are being freed, we use check points to |
| 424 // infer that the correct packets have been freed. |
| 425 { |
| 426 SCOPED_TRACE(""); |
| 427 InitializeDemuxer(); |
| 428 } |
| 429 |
| 430 // Get our streams. |
| 431 scoped_refptr<DemuxerStream> video = demuxer_->GetStream(DS_STREAM_VIDEO); |
| 432 scoped_refptr<DemuxerStream> audio = demuxer_->GetStream(DS_STREAM_AUDIO); |
| 433 ASSERT_TRUE(video); |
| 434 ASSERT_TRUE(audio); |
| 435 |
| 436 // Expected values. |
| 437 const int64 kExpectedTimestamp = 1234; |
| 438 const int64 kExpectedFlags = 0; |
| 439 |
| 440 // Expect all calls in sequence. |
| 441 InSequence s; |
| 442 |
| 443 // First we'll read a video packet that causes two audio packets to be queued |
| 444 // inside FFmpegDemuxer... |
| 445 EXPECT_CALL(*MockFFmpeg::get(), AVReadFrame(&format_context_, _)) |
| 446 .WillOnce(CreatePacket(AV_STREAM_AUDIO, kAudioData, kDataSize)); |
| 447 EXPECT_CALL(*MockFFmpeg::get(), AVReadFrame(&format_context_, _)) |
| 448 .WillOnce(CreatePacket(AV_STREAM_AUDIO, kAudioData, kDataSize)); |
| 449 EXPECT_CALL(*MockFFmpeg::get(), AVReadFrame(&format_context_, _)) |
| 450 .WillOnce(CreatePacket(AV_STREAM_VIDEO, kVideoData, kDataSize)); |
| 451 |
| 452 // ...then we'll release our video packet... |
| 453 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)).WillOnce(FreePacket()); |
| 454 EXPECT_CALL(*MockFFmpeg::get(), CheckPoint(1)); |
| 455 |
| 456 // ...then we'll seek, which should release the previously queued packets... |
| 457 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)).WillOnce(FreePacket()); |
| 458 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)).WillOnce(FreePacket()); |
| 459 |
| 460 // ...then we'll expect the actual seek call... |
| 461 EXPECT_CALL(*MockFFmpeg::get(), |
| 462 AVSeekFrame(&format_context_, -1, kExpectedTimestamp, kExpectedFlags)) |
| 463 .WillOnce(Return(0)); |
| 464 EXPECT_CALL(*MockFFmpeg::get(), CheckPoint(2)); |
| 465 |
| 466 // ...followed by two audio packet reads we'll trigger... |
| 467 EXPECT_CALL(*MockFFmpeg::get(), AVReadFrame(&format_context_, _)) |
| 468 .WillOnce(CreatePacket(AV_STREAM_AUDIO, kAudioData, kDataSize)); |
| 469 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)).WillOnce(FreePacket()); |
| 470 EXPECT_CALL(*MockFFmpeg::get(), AVReadFrame(&format_context_, _)) |
| 471 .WillOnce(CreatePacket(AV_STREAM_AUDIO, kAudioData, kDataSize)); |
| 472 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)).WillOnce(FreePacket()); |
| 473 |
| 474 // ...followed by two video packet reads... |
| 475 EXPECT_CALL(*MockFFmpeg::get(), AVReadFrame(&format_context_, _)) |
| 476 .WillOnce(CreatePacket(AV_STREAM_VIDEO, kVideoData, kDataSize)); |
| 477 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)).WillOnce(FreePacket()); |
| 478 EXPECT_CALL(*MockFFmpeg::get(), AVReadFrame(&format_context_, _)) |
| 479 .WillOnce(CreatePacket(AV_STREAM_VIDEO, kVideoData, kDataSize)); |
| 480 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)).WillOnce(FreePacket()); |
| 481 |
| 482 // ...and finally a sanity checkpoint to make sure everything was released. |
| 483 EXPECT_CALL(*MockFFmpeg::get(), CheckPoint(3)); |
| 484 |
| 485 // Read a video packet and release it. |
| 486 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
| 487 reader->Read(video); |
| 488 pipeline_->RunAllTasks(); |
| 489 EXPECT_TRUE(reader->WaitForRead()); |
| 490 EXPECT_TRUE(reader->called()); |
| 491 ASSERT_TRUE(reader->buffer()); |
| 492 EXPECT_FALSE(reader->buffer()->IsDiscontinuous()); |
| 493 EXPECT_EQ(kVideoData, reader->buffer()->GetData()); |
| 494 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 495 |
| 496 // Release the video packet and verify the other packets are still queued. |
| 497 reader->Reset(); |
| 498 WaitForDemuxerThread(); |
| 499 MockFFmpeg::get()->CheckPoint(1); |
| 500 |
| 501 // Now issue a simple forward seek, which should discard queued packets. |
| 502 demuxer_->Seek(base::TimeDelta::FromMicroseconds(kExpectedTimestamp)); |
| 503 WaitForDemuxerThread(); |
| 504 MockFFmpeg::get()->CheckPoint(2); |
| 465 | 505 |
| 466 // The next read from each stream should now be discontinuous, but subsequent | 506 // The next read from each stream should now be discontinuous, but subsequent |
| 467 // reads should not. | 507 // reads should not. |
| 468 | 508 |
| 469 // Prepare our test audio packet. | |
| 470 PacketQueue::get()->Enqueue(kPacketAudio, kDataSize, audio_data); | |
| 471 PacketQueue::get()->Enqueue(kPacketAudio, kDataSize, audio_data); | |
| 472 | |
| 473 // Audio read #1, should be discontinuous. | 509 // Audio read #1, should be discontinuous. |
| 474 reader = new DemuxerStreamReader(); | 510 reader->Read(audio); |
| 475 reader->Read(audio_stream); | |
| 476 pipeline_->RunAllTasks(); | 511 pipeline_->RunAllTasks(); |
| 477 EXPECT_TRUE(reader->WaitForRead()); | 512 EXPECT_TRUE(reader->WaitForRead()); |
| 478 EXPECT_TRUE(reader->called()); | 513 EXPECT_TRUE(reader->called()); |
| 479 ASSERT_TRUE(reader->buffer()); | 514 ASSERT_TRUE(reader->buffer()); |
| 480 EXPECT_TRUE(reader->buffer()->IsDiscontinuous()); | 515 EXPECT_TRUE(reader->buffer()->IsDiscontinuous()); |
| 481 EXPECT_EQ(audio_data, reader->buffer()->GetData()); | 516 EXPECT_EQ(kAudioData, reader->buffer()->GetData()); |
| 482 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); | 517 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 483 | 518 |
| 484 // Audio read #2, should not be discontinuous. | 519 // Audio read #2, should not be discontinuous. |
| 485 reader->Reset(); | 520 reader->Reset(); |
| 486 reader->Read(audio_stream); | 521 reader->Read(audio); |
| 487 pipeline_->RunAllTasks(); | 522 pipeline_->RunAllTasks(); |
| 488 EXPECT_TRUE(reader->WaitForRead()); | 523 EXPECT_TRUE(reader->WaitForRead()); |
| 489 EXPECT_TRUE(reader->called()); | 524 EXPECT_TRUE(reader->called()); |
| 490 ASSERT_TRUE(reader->buffer()); | 525 ASSERT_TRUE(reader->buffer()); |
| 491 EXPECT_FALSE(reader->buffer()->IsDiscontinuous()); | 526 EXPECT_FALSE(reader->buffer()->IsDiscontinuous()); |
| 492 EXPECT_EQ(audio_data, reader->buffer()->GetData()); | 527 EXPECT_EQ(kAudioData, reader->buffer()->GetData()); |
| 493 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); | 528 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 494 | |
| 495 // Prepare our test video packet. | |
| 496 PacketQueue::get()->Enqueue(kPacketVideo, kDataSize, video_data); | |
| 497 PacketQueue::get()->Enqueue(kPacketVideo, kDataSize, video_data); | |
| 498 | 529 |
| 499 // Video read #1, should be discontinuous. | 530 // Video read #1, should be discontinuous. |
| 500 reader->Reset(); | 531 reader->Reset(); |
| 501 reader->Read(video_stream); | 532 reader->Read(video); |
| 502 pipeline_->RunAllTasks(); | 533 pipeline_->RunAllTasks(); |
| 503 EXPECT_TRUE(reader->WaitForRead()); | 534 EXPECT_TRUE(reader->WaitForRead()); |
| 504 EXPECT_TRUE(reader->called()); | 535 EXPECT_TRUE(reader->called()); |
| 505 ASSERT_TRUE(reader->buffer()); | 536 ASSERT_TRUE(reader->buffer()); |
| 506 EXPECT_TRUE(reader->buffer()->IsDiscontinuous()); | 537 EXPECT_TRUE(reader->buffer()->IsDiscontinuous()); |
| 507 EXPECT_EQ(video_data, reader->buffer()->GetData()); | 538 EXPECT_EQ(kVideoData, reader->buffer()->GetData()); |
| 508 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); | 539 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 509 | 540 |
| 510 // Video read #2, should not be discontinuous. | 541 // Video read #2, should not be discontinuous. |
| 511 reader->Reset(); | 542 reader->Reset(); |
| 512 reader->Read(video_stream); | 543 reader->Read(video); |
| 513 pipeline_->RunAllTasks(); | 544 pipeline_->RunAllTasks(); |
| 514 EXPECT_TRUE(reader->WaitForRead()); | 545 EXPECT_TRUE(reader->WaitForRead()); |
| 515 EXPECT_TRUE(reader->called()); | 546 EXPECT_TRUE(reader->called()); |
| 516 ASSERT_TRUE(reader->buffer()); | 547 ASSERT_TRUE(reader->buffer()); |
| 517 EXPECT_FALSE(reader->buffer()->IsDiscontinuous()); | 548 EXPECT_FALSE(reader->buffer()->IsDiscontinuous()); |
| 518 EXPECT_EQ(video_data, reader->buffer()->GetData()); | 549 EXPECT_EQ(kVideoData, reader->buffer()->GetData()); |
| 519 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); | 550 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 520 | 551 |
| 521 // Manually release buffer, which should release any remaining AVPackets. | 552 // Manually release the last reference to the buffer and verify it was freed. |
| 522 reader = NULL; | 553 reader->Reset(); |
| 523 EXPECT_TRUE(PacketQueue::get()->WaitForOutstandingPackets(0)); | 554 WaitForDemuxerThread(); |
| 524 | 555 MockFFmpeg::get()->CheckPoint(3); |
| 525 // Let's trigger another simple forward seek, but with outstanding packets. | |
| 526 // The outstanding packets should get freed after the Seek() is issued. | |
| 527 PacketQueue::get()->Enqueue(kPacketAudio, kDataSize, audio_data); | |
| 528 PacketQueue::get()->Enqueue(kPacketAudio, kDataSize, audio_data); | |
| 529 PacketQueue::get()->Enqueue(kPacketAudio, kDataSize, audio_data); | |
| 530 PacketQueue::get()->Enqueue(kPacketVideo, kDataSize, video_data); | |
| 531 | |
| 532 // Attempt a read from video stream, which will force the demuxer to queue | |
| 533 // the audio packets preceding the video packet. | |
| 534 reader = new DemuxerStreamReader(); | |
| 535 reader->Read(video_stream); | |
| 536 pipeline_->RunAllTasks(); | |
| 537 EXPECT_TRUE(reader->WaitForRead()); | |
| 538 EXPECT_TRUE(reader->called()); | |
| 539 ASSERT_TRUE(reader->buffer()); | |
| 540 EXPECT_FALSE(reader->buffer()->IsDiscontinuous()); | |
| 541 EXPECT_EQ(video_data, reader->buffer()->GetData()); | |
| 542 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); | |
| 543 | |
| 544 // Manually release video buffer, remaining audio packets are outstanding. | |
| 545 reader = NULL; | |
| 546 EXPECT_TRUE(PacketQueue::get()->WaitForOutstandingPackets(3)); | |
| 547 | |
| 548 // Trigger the seek. | |
| 549 g_expected_seek_timestamp = 1234; | |
| 550 g_expected_seek_flags = 0; | |
| 551 demuxer_->Seek(base::TimeDelta::FromMicroseconds(g_expected_seek_timestamp)); | |
| 552 EXPECT_TRUE(g_seek_event->TimedWait(base::TimeDelta::FromSeconds(1))); | |
| 553 | |
| 554 // All outstanding packets should have been freed. | |
| 555 EXPECT_TRUE(PacketQueue::get()->WaitForOutstandingPackets(0)); | |
| 556 | |
| 557 // Clean up. | |
| 558 delete g_seek_event; | |
| 559 g_seek_event = NULL; | |
| 560 | |
| 561 //---------------------------------------------------------------------------- | |
| 562 // End of stream tests. | |
| 563 | |
| 564 // Simulate end of stream. | |
| 565 g_av_read_frame = AVERROR_IO; | |
| 566 | |
| 567 // Attempt a read from the audio stream and run the message loop until done. | |
| 568 reader = new DemuxerStreamReader(); | |
| 569 reader->Read(audio_stream); | |
| 570 pipeline_->RunAllTasks(); | |
| 571 EXPECT_TRUE(reader->WaitForRead()); | |
| 572 EXPECT_TRUE(reader->called()); | |
| 573 ASSERT_TRUE(reader->buffer()); | |
| 574 EXPECT_TRUE(reader->buffer()->IsEndOfStream()); | |
| 575 | |
| 576 // Manually release buffer, which should release any remaining AVPackets. | |
| 577 reader = NULL; | |
| 578 EXPECT_TRUE(PacketQueue::get()->WaitForOutstandingPackets(0)); | |
| 579 } | 556 } |
| 580 | 557 |
| 581 // This tests our deep-copying workaround for FFmpeg's MP3 demuxer. When we fix | 558 TEST_F(FFmpegDemuxerTest, MP3Hack) { |
| 582 // the root cause this test will fail and should be removed. | 559 // This tests our deep-copying workaround for FFmpeg's MP3 demuxer. When we |
| 583 // | 560 // fix the root cause this test will fail and should be removed. |
| 584 // TODO(scherkus): disabled due to flakiness http://crbug.com/13933 | 561 // |
| 585 TEST_F(FFmpegDemuxerTest, DISABLED_MP3Hack) { | 562 // TODO(scherkus): according to the documentation, deep-copying the packet is |
| 586 // Prepare some test data. | 563 // actually the correct action -- remove this test when we fix our demuxer. |
| 587 const int kPacketAudio = 0; // Stream index relative to the container. | 564 |
| 588 const int kAudio = 0; // Stream index relative to Demuxer::GetStream(). | 565 // Simulate an MP3 stream. |
| 589 const size_t kDataSize = 4; | 566 codecs_[AV_STREAM_AUDIO].codec_id = CODEC_ID_MP3; |
| 590 uint8 audio_data[kDataSize] = {0, 1, 2, 3}; | 567 { |
| 591 | 568 SCOPED_TRACE(""); |
| 592 // Simulate media with a single MP3 audio stream. | 569 InitializeDemuxer(); |
| 593 g_format.nb_streams = 1; | 570 } |
| 594 g_format.streams[kPacketAudio] = &g_streams[0]; | 571 |
| 595 g_streams[0].duration = 10; | 572 // Get our stream. |
| 596 g_streams[0].codec = &g_audio_codec; | 573 scoped_refptr<DemuxerStream> audio = demuxer_->GetStream(DS_STREAM_AUDIO); |
| 597 g_audio_codec.codec_id = CODEC_ID_MP3; | 574 ASSERT_TRUE(audio); |
| 598 | 575 |
| 599 // Initialize the demuxer. | 576 // Expect all calls in sequence. |
| 600 EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); | 577 InSequence s; |
| 601 EXPECT_TRUE(filter_host_->WaitForInitialized()); | 578 |
| 602 EXPECT_TRUE(filter_host_->IsInitialized()); | 579 // We'll read an MP3 packet and allocate a new packet, then instantly free |
| 603 EXPECT_EQ(PIPELINE_OK, pipeline_->GetError()); | 580 // the original packet due to deep copying... |
| 604 | 581 EXPECT_CALL(*MockFFmpeg::get(), AVReadFrame(&format_context_, _)) |
| 605 // Verify the stream was created. | 582 .WillOnce(CreatePacket(AV_STREAM_AUDIO, kAudioData, kDataSize)); |
| 606 EXPECT_EQ(1u, demuxer_->GetNumberOfStreams()); | 583 EXPECT_CALL(*MockFFmpeg::get(), AVNewPacket(_, _)).WillOnce(NewPacket()); |
| 607 scoped_refptr<DemuxerStream> audio_stream = demuxer_->GetStream(kAudio); | 584 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)).WillOnce(FreePacket()); |
| 608 ASSERT_TRUE(audio_stream); | 585 |
| 609 | 586 // ...then we'll have a sanity checkpoint... |
| 610 // Prepare our test audio packet. | 587 EXPECT_CALL(*MockFFmpeg::get(), CheckPoint(1)); |
| 611 PacketQueue::get()->Enqueue(kPacketAudio, kDataSize, audio_data); | 588 |
| 589 // ...then we'll free the deep copied packet. |
| 590 EXPECT_CALL(*MockFFmpeg::get(), AVFreePacket(_)).WillOnce(FreePacket()); |
| 591 EXPECT_CALL(*MockFFmpeg::get(), CheckPoint(2)); |
| 612 | 592 |
| 613 // Audio read should perform a deep copy on the packet and instantly release | 593 // Audio read should perform a deep copy on the packet and instantly release |
| 614 // the original packet. The data pointers should not be the same, but the | 594 // the original packet. The data pointers should not be the same, but the |
| 615 // contents should match. | 595 // contents should match. |
| 616 scoped_refptr<DemuxerStreamReader> reader = new DemuxerStreamReader(); | 596 scoped_refptr<DemuxerStreamReader> reader = new DemuxerStreamReader(); |
| 617 reader->Read(audio_stream); | 597 reader->Read(audio); |
| 618 pipeline_->RunAllTasks(); | 598 pipeline_->RunAllTasks(); |
| 619 EXPECT_TRUE(reader->WaitForRead()); | 599 EXPECT_TRUE(reader->WaitForRead()); |
| 620 EXPECT_TRUE(reader->called()); | 600 EXPECT_TRUE(reader->called()); |
| 621 ASSERT_TRUE(reader->buffer()); | 601 ASSERT_TRUE(reader->buffer()); |
| 622 EXPECT_FALSE(reader->buffer()->IsDiscontinuous()); | 602 EXPECT_FALSE(reader->buffer()->IsDiscontinuous()); |
| 623 EXPECT_NE(audio_data, reader->buffer()->GetData()); | 603 EXPECT_NE(kAudioData, reader->buffer()->GetData()); |
| 624 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); | 604 EXPECT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 625 EXPECT_EQ(0, memcmp(audio_data, reader->buffer()->GetData(), kDataSize)); | 605 EXPECT_EQ(0, memcmp(kAudioData, reader->buffer()->GetData(), kDataSize)); |
| 626 | 606 |
| 627 // Original AVPacket from the queue should have been released due to copying. | 607 // We shouldn't have freed the MP3 packet yet. |
| 628 EXPECT_TRUE(PacketQueue::get()->WaitForOutstandingPackets(0)); | 608 MockFFmpeg::get()->CheckPoint(1); |
| 629 EXPECT_EQ(1, g_outstanding_packets_av_new_frame); | 609 |
| 630 | 610 // Manually release the last reference to the buffer and verify it was freed. |
| 631 // Now release our reference, which should destruct the packet allocated by | 611 reader->Reset(); |
| 632 // av_new_packet(). | 612 WaitForDemuxerThread(); |
| 633 reader = NULL; | 613 MockFFmpeg::get()->CheckPoint(2); |
| 634 EXPECT_EQ(0, g_outstanding_packets_av_new_frame); | |
| 635 } | 614 } |
| 636 | 615 |
| 637 } // namespace media | 616 } // namespace media |
| OLD | NEW |