| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 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 "media/cast/test/fake_media_source.h" | 5 #include "media/cast/test/fake_media_source.h" |
| 6 | 6 |
| 7 #include "base/files/memory_mapped_file.h" | 7 #include "base/files/memory_mapped_file.h" |
| 8 #include "base/files/scoped_file.h" | 8 #include "base/files/scoped_file.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/rand_util.h" | 10 #include "base/rand_util.h" |
| 11 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
| 12 #include "media/audio/audio_parameters.h" | 12 #include "media/audio/audio_parameters.h" |
| 13 #include "media/base/audio_buffer.h" | 13 #include "media/base/audio_buffer.h" |
| 14 #include "media/base/audio_bus.h" | 14 #include "media/base/audio_bus.h" |
| 15 #include "media/base/audio_fifo.h" | 15 #include "media/base/audio_fifo.h" |
| 16 #include "media/base/audio_timestamp_helper.h" | 16 #include "media/base/audio_timestamp_helper.h" |
| 17 #include "media/base/media.h" | 17 #include "media/base/media.h" |
| 18 #include "media/base/multi_channel_resampler.h" | |
| 19 #include "media/base/video_frame.h" | 18 #include "media/base/video_frame.h" |
| 20 #include "media/base/video_util.h" | 19 #include "media/base/video_util.h" |
| 21 #include "media/cast/cast_sender.h" | 20 #include "media/cast/cast_sender.h" |
| 22 #include "media/cast/test/utility/audio_utility.h" | 21 #include "media/cast/test/utility/audio_utility.h" |
| 23 #include "media/cast/test/utility/video_utility.h" | 22 #include "media/cast/test/utility/video_utility.h" |
| 24 #include "media/ffmpeg/ffmpeg_common.h" | 23 #include "media/ffmpeg/ffmpeg_common.h" |
| 25 #include "media/ffmpeg/ffmpeg_deleters.h" | 24 #include "media/ffmpeg/ffmpeg_deleters.h" |
| 26 #include "media/filters/audio_renderer_algorithm.h" | 25 #include "media/filters/audio_renderer_algorithm.h" |
| 27 #include "media/filters/ffmpeg_demuxer.h" | 26 #include "media/filters/ffmpeg_demuxer.h" |
| 28 #include "media/filters/ffmpeg_glue.h" | 27 #include "media/filters/ffmpeg_glue.h" |
| 29 #include "media/filters/in_memory_url_protocol.h" | 28 #include "media/filters/in_memory_url_protocol.h" |
| 30 #include "ui/gfx/geometry/size.h" | 29 #include "ui/gfx/geometry/size.h" |
| 31 | 30 |
| 32 namespace { | 31 namespace { |
| 33 | 32 |
| 34 static const int kAudioChannels = 2; | |
| 35 static const int kAudioSamplingFrequency = 48000; | |
| 36 static const int kSoundFrequency = 440; // Frequency of sinusoid wave. | 33 static const int kSoundFrequency = 440; // Frequency of sinusoid wave. |
| 37 static const float kSoundVolume = 0.10f; | 34 static const float kSoundVolume = 0.10f; |
| 38 static const int kAudioFrameMs = 10; // Each audio frame is exactly 10ms. | 35 static const int kAudioFrameMs = 10; // Each audio frame is exactly 10ms. |
| 39 static const int kAudioPacketsPerSecond = 1000 / kAudioFrameMs; | 36 static const int kAudioPacketsPerSecond = 1000 / kAudioFrameMs; |
| 40 | 37 |
| 41 // Bounds for variable frame size mode. | 38 // Bounds for variable frame size mode. |
| 42 static const int kMinFakeFrameWidth = 60; | 39 static const int kMinFakeFrameWidth = 60; |
| 43 static const int kMinFakeFrameHeight = 34; | 40 static const int kMinFakeFrameHeight = 34; |
| 44 static const int kStartingFakeFrameWidth = 854; | 41 static const int kStartingFakeFrameWidth = 854; |
| 45 static const int kStartingFakeFrameHeight = 480; | 42 static const int kStartingFakeFrameHeight = 480; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 62 } | 59 } |
| 63 | 60 |
| 64 } // namespace | 61 } // namespace |
| 65 | 62 |
| 66 namespace media { | 63 namespace media { |
| 67 namespace cast { | 64 namespace cast { |
| 68 | 65 |
| 69 FakeMediaSource::FakeMediaSource( | 66 FakeMediaSource::FakeMediaSource( |
| 70 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | 67 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| 71 base::TickClock* clock, | 68 base::TickClock* clock, |
| 69 const AudioSenderConfig& audio_config, |
| 72 const VideoSenderConfig& video_config, | 70 const VideoSenderConfig& video_config, |
| 73 bool keep_frames) | 71 bool keep_frames) |
| 74 : task_runner_(task_runner), | 72 : task_runner_(task_runner), |
| 73 output_audio_params_(AudioParameters::AUDIO_PCM_LINEAR, |
| 74 media::GuessChannelLayout(audio_config.channels), |
| 75 audio_config.frequency, |
| 76 32, |
| 77 audio_config.frequency / kAudioPacketsPerSecond), |
| 75 video_config_(video_config), | 78 video_config_(video_config), |
| 76 keep_frames_(keep_frames), | 79 keep_frames_(keep_frames), |
| 77 variable_frame_size_mode_(false), | 80 variable_frame_size_mode_(false), |
| 78 synthetic_count_(0), | 81 synthetic_count_(0), |
| 79 clock_(clock), | 82 clock_(clock), |
| 80 audio_frame_count_(0), | 83 audio_frame_count_(0), |
| 81 video_frame_count_(0), | 84 video_frame_count_(0), |
| 82 av_format_context_(NULL), | 85 av_format_context_(NULL), |
| 83 audio_stream_index_(-1), | 86 audio_stream_index_(-1), |
| 84 playback_rate_(1.0), | 87 playback_rate_(1.0), |
| 85 video_stream_index_(-1), | 88 video_stream_index_(-1), |
| 86 video_frame_rate_numerator_(video_config.max_frame_rate), | 89 video_frame_rate_numerator_(video_config.max_frame_rate), |
| 87 video_frame_rate_denominator_(1), | 90 video_frame_rate_denominator_(1), |
| 88 video_first_pts_(0), | 91 video_first_pts_(0), |
| 89 video_first_pts_set_(false), | 92 video_first_pts_set_(false), |
| 90 weak_factory_(this) { | 93 weak_factory_(this) { |
| 91 audio_bus_factory_.reset(new TestAudioBusFactory(kAudioChannels, | 94 CHECK(output_audio_params_.IsValid()); |
| 92 kAudioSamplingFrequency, | 95 audio_bus_factory_.reset(new TestAudioBusFactory(audio_config.channels, |
| 96 audio_config.frequency, |
| 93 kSoundFrequency, | 97 kSoundFrequency, |
| 94 kSoundVolume)); | 98 kSoundVolume)); |
| 95 } | 99 } |
| 96 | 100 |
| 97 FakeMediaSource::~FakeMediaSource() { | 101 FakeMediaSource::~FakeMediaSource() { |
| 98 } | 102 } |
| 99 | 103 |
| 100 void FakeMediaSource::SetSourceFile(const base::FilePath& video_file, | 104 void FakeMediaSource::SetSourceFile(const base::FilePath& video_file, |
| 101 int override_fps) { | 105 int override_fps) { |
| 102 DCHECK(!video_file.empty()); | 106 DCHECK(!video_file.empty()); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 av_codec_context->channel_layout, | 158 av_codec_context->channel_layout, |
| 155 av_codec_context->channels); | 159 av_codec_context->channels); |
| 156 if (layout == CHANNEL_LAYOUT_UNSUPPORTED) { | 160 if (layout == CHANNEL_LAYOUT_UNSUPPORTED) { |
| 157 LOG(ERROR) << "Unsupported audio channels layout."; | 161 LOG(ERROR) << "Unsupported audio channels layout."; |
| 158 continue; | 162 continue; |
| 159 } | 163 } |
| 160 if (audio_stream_index_ != -1) { | 164 if (audio_stream_index_ != -1) { |
| 161 LOG(WARNING) << "Found multiple audio streams."; | 165 LOG(WARNING) << "Found multiple audio streams."; |
| 162 } | 166 } |
| 163 audio_stream_index_ = static_cast<int>(i); | 167 audio_stream_index_ = static_cast<int>(i); |
| 164 audio_params_.Reset( | 168 source_audio_params_.Reset( |
| 165 AudioParameters::AUDIO_PCM_LINEAR, | 169 AudioParameters::AUDIO_PCM_LINEAR, |
| 166 layout, | 170 layout, |
| 167 av_codec_context->channels, | 171 av_codec_context->channels, |
| 168 av_codec_context->sample_rate, | 172 av_codec_context->sample_rate, |
| 169 8 * av_get_bytes_per_sample(av_codec_context->sample_fmt), | 173 8 * av_get_bytes_per_sample(av_codec_context->sample_fmt), |
| 170 av_codec_context->sample_rate / kAudioPacketsPerSecond); | 174 av_codec_context->sample_rate / kAudioPacketsPerSecond); |
| 175 CHECK(source_audio_params_.IsValid()); |
| 171 LOG(INFO) << "Source file has audio."; | 176 LOG(INFO) << "Source file has audio."; |
| 172 } else if (av_codec->type == AVMEDIA_TYPE_VIDEO) { | 177 } else if (av_codec->type == AVMEDIA_TYPE_VIDEO) { |
| 173 VideoFrame::Format format = | 178 VideoFrame::Format format = |
| 174 PixelFormatToVideoFormat(av_codec_context->pix_fmt); | 179 PixelFormatToVideoFormat(av_codec_context->pix_fmt); |
| 175 if (format != VideoFrame::YV12) { | 180 if (format != VideoFrame::YV12) { |
| 176 LOG(ERROR) << "Cannot handle non YV12 video format: " << format; | 181 LOG(ERROR) << "Cannot handle non YV12 video format: " << format; |
| 177 continue; | 182 continue; |
| 178 } | 183 } |
| 179 if (video_stream_index_ != -1) { | 184 if (video_stream_index_ != -1) { |
| 180 LOG(WARNING) << "Found multiple video streams."; | 185 LOG(WARNING) << "Found multiple video streams."; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 if (!is_transcoding_audio() && !is_transcoding_video()) { | 226 if (!is_transcoding_audio() && !is_transcoding_video()) { |
| 222 // Send fake patterns. | 227 // Send fake patterns. |
| 223 task_runner_->PostTask( | 228 task_runner_->PostTask( |
| 224 FROM_HERE, | 229 FROM_HERE, |
| 225 base::Bind(&FakeMediaSource::SendNextFakeFrame, | 230 base::Bind(&FakeMediaSource::SendNextFakeFrame, |
| 226 weak_factory_.GetWeakPtr())); | 231 weak_factory_.GetWeakPtr())); |
| 227 return; | 232 return; |
| 228 } | 233 } |
| 229 | 234 |
| 230 // Send transcoding streams. | 235 // Send transcoding streams. |
| 231 audio_algo_.Initialize(audio_params_); | 236 audio_algo_.Initialize(source_audio_params_); |
| 232 audio_algo_.FlushBuffers(); | 237 audio_algo_.FlushBuffers(); |
| 233 audio_fifo_input_bus_ = | 238 audio_fifo_input_bus_ = AudioBus::Create( |
| 234 AudioBus::Create( | 239 source_audio_params_.channels(), |
| 235 audio_params_.channels(), audio_params_.frames_per_buffer()); | 240 source_audio_params_.frames_per_buffer()); |
| 236 // Audio FIFO can carry all data fron AudioRendererAlgorithm. | 241 // Audio FIFO can carry all data fron AudioRendererAlgorithm. |
| 237 audio_fifo_.reset( | 242 audio_fifo_.reset( |
| 238 new AudioFifo(audio_params_.channels(), | 243 new AudioFifo(source_audio_params_.channels(), |
| 239 audio_algo_.QueueCapacity())); | 244 audio_algo_.QueueCapacity())); |
| 240 audio_resampler_.reset(new media::MultiChannelResampler( | 245 audio_converter_.reset(new media::AudioConverter( |
| 241 audio_params_.channels(), | 246 source_audio_params_, output_audio_params_, true)); |
| 242 static_cast<double>(audio_params_.sample_rate()) / | 247 audio_converter_->AddInput(this); |
| 243 kAudioSamplingFrequency, | |
| 244 audio_params_.frames_per_buffer(), | |
| 245 base::Bind(&FakeMediaSource::ProvideData, weak_factory_.GetWeakPtr()))); | |
| 246 task_runner_->PostTask( | 248 task_runner_->PostTask( |
| 247 FROM_HERE, | 249 FROM_HERE, |
| 248 base::Bind(&FakeMediaSource::SendNextFrame, weak_factory_.GetWeakPtr())); | 250 base::Bind(&FakeMediaSource::SendNextFrame, weak_factory_.GetWeakPtr())); |
| 249 } | 251 } |
| 250 | 252 |
| 251 void FakeMediaSource::SendNextFakeFrame() { | 253 void FakeMediaSource::SendNextFakeFrame() { |
| 252 UpdateNextFrameSize(); | 254 UpdateNextFrameSize(); |
| 253 scoped_refptr<VideoFrame> video_frame = | 255 scoped_refptr<VideoFrame> video_frame = |
| 254 VideoFrame::CreateBlackFrame(current_frame_size_); | 256 VideoFrame::CreateBlackFrame(current_frame_size_); |
| 255 PopulateVideoFrame(video_frame.get(), synthetic_count_); | 257 PopulateVideoFrame(video_frame.get(), synthetic_count_); |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 int frames_read = avframe->nb_samples; | 457 int frames_read = avframe->nb_samples; |
| 456 if (frames_read < 0) | 458 if (frames_read < 0) |
| 457 break; | 459 break; |
| 458 | 460 |
| 459 if (!audio_sent_ts_) { | 461 if (!audio_sent_ts_) { |
| 460 // Initialize the base time to the first packet in the file. | 462 // Initialize the base time to the first packet in the file. |
| 461 // This is set to the frequency we send to the receiver. | 463 // This is set to the frequency we send to the receiver. |
| 462 // Not the frequency of the source file. This is because we | 464 // Not the frequency of the source file. This is because we |
| 463 // increment the frame count by samples we sent. | 465 // increment the frame count by samples we sent. |
| 464 audio_sent_ts_.reset( | 466 audio_sent_ts_.reset( |
| 465 new AudioTimestampHelper(kAudioSamplingFrequency)); | 467 new AudioTimestampHelper(output_audio_params_.sample_rate())); |
| 466 // For some files this is an invalid value. | 468 // For some files this is an invalid value. |
| 467 base::TimeDelta base_ts; | 469 base::TimeDelta base_ts; |
| 468 audio_sent_ts_->SetBaseTimestamp(base_ts); | 470 audio_sent_ts_->SetBaseTimestamp(base_ts); |
| 469 } | 471 } |
| 470 | 472 |
| 471 scoped_refptr<AudioBuffer> buffer = | 473 scoped_refptr<AudioBuffer> buffer = |
| 472 AudioBuffer::CopyFrom( | 474 AudioBuffer::CopyFrom( |
| 473 AVSampleFormatToSampleFormat( | 475 AVSampleFormatToSampleFormat( |
| 474 av_audio_context()->sample_fmt), | 476 av_audio_context()->sample_fmt), |
| 475 ChannelLayoutToChromeChannelLayout( | 477 ChannelLayoutToChromeChannelLayout( |
| (...skipping 23 matching lines...) Expand all Loading... |
| 499 // Prevent overflow of audio data in the FIFO. | 501 // Prevent overflow of audio data in the FIFO. |
| 500 if (audio_fifo_input_bus_->frames() + audio_fifo_->frames() | 502 if (audio_fifo_input_bus_->frames() + audio_fifo_->frames() |
| 501 <= audio_fifo_->max_frames()) { | 503 <= audio_fifo_->max_frames()) { |
| 502 audio_fifo_->Push(audio_fifo_input_bus_.get()); | 504 audio_fifo_->Push(audio_fifo_input_bus_.get()); |
| 503 } else { | 505 } else { |
| 504 LOG(WARNING) << "Audio FIFO full; dropping samples."; | 506 LOG(WARNING) << "Audio FIFO full; dropping samples."; |
| 505 } | 507 } |
| 506 | 508 |
| 507 // Make sure there's enough data to resample audio. | 509 // Make sure there's enough data to resample audio. |
| 508 if (audio_fifo_->frames() < | 510 if (audio_fifo_->frames() < |
| 509 2 * audio_params_.sample_rate() / kAudioPacketsPerSecond) { | 511 2 * source_audio_params_.sample_rate() / kAudioPacketsPerSecond) { |
| 510 continue; | 512 continue; |
| 511 } | 513 } |
| 512 | 514 |
| 513 scoped_ptr<media::AudioBus> resampled_bus( | 515 scoped_ptr<media::AudioBus> resampled_bus( |
| 514 media::AudioBus::Create( | 516 media::AudioBus::Create( |
| 515 audio_params_.channels(), | 517 output_audio_params_.channels(), |
| 516 kAudioSamplingFrequency / kAudioPacketsPerSecond)); | 518 output_audio_params_.sample_rate() / kAudioPacketsPerSecond)); |
| 517 audio_resampler_->Resample(resampled_bus->frames(), | 519 audio_converter_->Convert(resampled_bus.get()); |
| 518 resampled_bus.get()); | |
| 519 audio_bus_queue_.push(resampled_bus.release()); | 520 audio_bus_queue_.push(resampled_bus.release()); |
| 520 } | 521 } |
| 521 } | 522 } |
| 522 | 523 |
| 523 void FakeMediaSource::DecodeVideo(ScopedAVPacket packet) { | 524 void FakeMediaSource::DecodeVideo(ScopedAVPacket packet) { |
| 524 // Video. | 525 // Video. |
| 525 int got_picture; | 526 int got_picture; |
| 526 AVFrame* avframe = av_frame_alloc(); | 527 AVFrame* avframe = av_frame_alloc(); |
| 527 CHECK(avcodec_decode_video2( | 528 CHECK(avcodec_decode_video2( |
| 528 av_video_context(), avframe, &got_picture, packet.get()) >= 0) | 529 av_video_context(), avframe, &got_picture, packet.get()) >= 0) |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 581 return; | 582 return; |
| 582 } | 583 } |
| 583 | 584 |
| 584 if (audio_packet) | 585 if (audio_packet) |
| 585 DecodeAudio(packet.Pass()); | 586 DecodeAudio(packet.Pass()); |
| 586 else | 587 else |
| 587 DecodeVideo(packet.Pass()); | 588 DecodeVideo(packet.Pass()); |
| 588 } | 589 } |
| 589 } | 590 } |
| 590 | 591 |
| 591 void FakeMediaSource::ProvideData(int frame_delay, | 592 double FakeMediaSource::ProvideInput(media::AudioBus* output_bus, |
| 592 media::AudioBus* output_bus) { | 593 base::TimeDelta buffer_delay) { |
| 593 if (audio_fifo_->frames() >= output_bus->frames()) { | 594 if (audio_fifo_->frames() >= output_bus->frames()) { |
| 594 audio_fifo_->Consume(output_bus, 0, output_bus->frames()); | 595 audio_fifo_->Consume(output_bus, 0, output_bus->frames()); |
| 596 return 1.0; |
| 595 } else { | 597 } else { |
| 596 LOG(WARNING) << "Not enough audio data for resampling."; | 598 LOG(WARNING) << "Not enough audio data for resampling."; |
| 597 output_bus->Zero(); | 599 output_bus->Zero(); |
| 600 return 0.0; |
| 598 } | 601 } |
| 599 } | 602 } |
| 600 | 603 |
| 601 scoped_refptr<media::VideoFrame> | 604 scoped_refptr<media::VideoFrame> |
| 602 FakeMediaSource::PopOldestInsertedVideoFrame() { | 605 FakeMediaSource::PopOldestInsertedVideoFrame() { |
| 603 CHECK(!inserted_video_frame_queue_.empty()); | 606 CHECK(!inserted_video_frame_queue_.empty()); |
| 604 scoped_refptr<media::VideoFrame> video_frame = | 607 scoped_refptr<media::VideoFrame> video_frame = |
| 605 inserted_video_frame_queue_.front(); | 608 inserted_video_frame_queue_.front(); |
| 606 inserted_video_frame_queue_.pop(); | 609 inserted_video_frame_queue_.pop(); |
| 607 return video_frame; | 610 return video_frame; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 618 AVCodecContext* FakeMediaSource::av_audio_context() { | 621 AVCodecContext* FakeMediaSource::av_audio_context() { |
| 619 return av_audio_stream()->codec; | 622 return av_audio_stream()->codec; |
| 620 } | 623 } |
| 621 | 624 |
| 622 AVCodecContext* FakeMediaSource::av_video_context() { | 625 AVCodecContext* FakeMediaSource::av_video_context() { |
| 623 return av_video_stream()->codec; | 626 return av_video_stream()->codec; |
| 624 } | 627 } |
| 625 | 628 |
| 626 } // namespace cast | 629 } // namespace cast |
| 627 } // namespace media | 630 } // namespace media |
| OLD | NEW |