Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / media / cast / test / fake_media_source.cc
blob061478d37fc504e25dc8d3ad6e9ea8a938540c83
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/cast/test/fake_media_source.h"
7 #include "base/files/memory_mapped_file.h"
8 #include "base/files/scoped_file.h"
9 #include "base/logging.h"
10 #include "base/rand_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "media/audio/audio_parameters.h"
13 #include "media/base/audio_buffer.h"
14 #include "media/base/audio_bus.h"
15 #include "media/base/audio_fifo.h"
16 #include "media/base/audio_timestamp_helper.h"
17 #include "media/base/media.h"
18 #include "media/base/video_frame.h"
19 #include "media/base/video_util.h"
20 #include "media/cast/cast_sender.h"
21 #include "media/cast/test/utility/audio_utility.h"
22 #include "media/cast/test/utility/video_utility.h"
23 #include "media/ffmpeg/ffmpeg_common.h"
24 #include "media/ffmpeg/ffmpeg_deleters.h"
25 #include "media/filters/audio_renderer_algorithm.h"
26 #include "media/filters/ffmpeg_demuxer.h"
27 #include "media/filters/ffmpeg_glue.h"
28 #include "media/filters/in_memory_url_protocol.h"
29 #include "ui/gfx/geometry/size.h"
31 namespace {
33 static const int kSoundFrequency = 440; // Frequency of sinusoid wave.
34 static const float kSoundVolume = 0.10f;
35 static const int kAudioFrameMs = 10; // Each audio frame is exactly 10ms.
36 static const int kAudioPacketsPerSecond = 1000 / kAudioFrameMs;
38 // Bounds for variable frame size mode.
39 static const int kMinFakeFrameWidth = 60;
40 static const int kMinFakeFrameHeight = 34;
41 static const int kStartingFakeFrameWidth = 854;
42 static const int kStartingFakeFrameHeight = 480;
43 static const int kMaxFakeFrameWidth = 1280;
44 static const int kMaxFakeFrameHeight = 720;
45 static const int kMaxFrameSizeChangeMillis = 5000;
47 void AVFreeFrame(AVFrame* frame) {
48 av_frame_free(&frame);
51 base::TimeDelta PtsToTimeDelta(int64 pts, const AVRational& time_base) {
52 return pts * base::TimeDelta::FromSeconds(1) * time_base.num / time_base.den;
55 int64 TimeDeltaToPts(base::TimeDelta delta, const AVRational& time_base) {
56 return static_cast<int64>(
57 delta.InSecondsF() * time_base.den / time_base.num +
58 0.5 /* rounding */);
61 } // namespace
63 namespace media {
64 namespace cast {
66 FakeMediaSource::FakeMediaSource(
67 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
68 base::TickClock* clock,
69 const AudioSenderConfig& audio_config,
70 const VideoSenderConfig& video_config,
71 bool keep_frames)
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),
78 video_config_(video_config),
79 keep_frames_(keep_frames),
80 variable_frame_size_mode_(false),
81 synthetic_count_(0),
82 clock_(clock),
83 audio_frame_count_(0),
84 video_frame_count_(0),
85 av_format_context_(NULL),
86 audio_stream_index_(-1),
87 playback_rate_(1.0),
88 video_stream_index_(-1),
89 video_frame_rate_numerator_(video_config.max_frame_rate),
90 video_frame_rate_denominator_(1),
91 video_first_pts_(0),
92 video_first_pts_set_(false),
93 weak_factory_(this) {
94 CHECK(output_audio_params_.IsValid());
95 audio_bus_factory_.reset(new TestAudioBusFactory(audio_config.channels,
96 audio_config.frequency,
97 kSoundFrequency,
98 kSoundVolume));
101 FakeMediaSource::~FakeMediaSource() {
104 void FakeMediaSource::SetSourceFile(const base::FilePath& video_file,
105 int override_fps) {
106 DCHECK(!video_file.empty());
108 LOG(INFO) << "Source: " << video_file.value();
109 if (!file_data_.Initialize(video_file)) {
110 LOG(ERROR) << "Cannot load file.";
111 return;
113 protocol_.reset(
114 new InMemoryUrlProtocol(file_data_.data(), file_data_.length(), false));
115 glue_.reset(new FFmpegGlue(protocol_.get()));
117 if (!glue_->OpenContext()) {
118 LOG(ERROR) << "Cannot open file.";
119 return;
122 // AVFormatContext is owned by the glue.
123 av_format_context_ = glue_->format_context();
124 if (avformat_find_stream_info(av_format_context_, NULL) < 0) {
125 LOG(ERROR) << "Cannot find stream information.";
126 return;
129 // Prepare FFmpeg decoders.
130 for (unsigned int i = 0; i < av_format_context_->nb_streams; ++i) {
131 AVStream* av_stream = av_format_context_->streams[i];
132 AVCodecContext* av_codec_context = av_stream->codec;
133 AVCodec* av_codec = avcodec_find_decoder(av_codec_context->codec_id);
135 if (!av_codec) {
136 LOG(ERROR) << "Cannot find decoder for the codec: "
137 << av_codec_context->codec_id;
138 continue;
141 // Number of threads for decoding.
142 av_codec_context->thread_count = 2;
143 av_codec_context->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
144 av_codec_context->request_sample_fmt = AV_SAMPLE_FMT_S16;
146 if (avcodec_open2(av_codec_context, av_codec, NULL) < 0) {
147 LOG(ERROR) << "Cannot open AVCodecContext for the codec: "
148 << av_codec_context->codec_id;
149 return;
152 if (av_codec->type == AVMEDIA_TYPE_AUDIO) {
153 if (av_codec_context->sample_fmt == AV_SAMPLE_FMT_S16P) {
154 LOG(ERROR) << "Audio format not supported.";
155 continue;
157 ChannelLayout layout = ChannelLayoutToChromeChannelLayout(
158 av_codec_context->channel_layout,
159 av_codec_context->channels);
160 if (layout == CHANNEL_LAYOUT_UNSUPPORTED) {
161 LOG(ERROR) << "Unsupported audio channels layout.";
162 continue;
164 if (audio_stream_index_ != -1) {
165 LOG(WARNING) << "Found multiple audio streams.";
167 audio_stream_index_ = static_cast<int>(i);
168 source_audio_params_.Reset(
169 AudioParameters::AUDIO_PCM_LINEAR,
170 layout,
171 av_codec_context->channels,
172 av_codec_context->sample_rate,
173 8 * av_get_bytes_per_sample(av_codec_context->sample_fmt),
174 av_codec_context->sample_rate / kAudioPacketsPerSecond);
175 CHECK(source_audio_params_.IsValid());
176 LOG(INFO) << "Source file has audio.";
177 } else if (av_codec->type == AVMEDIA_TYPE_VIDEO) {
178 VideoFrame::Format format =
179 PixelFormatToVideoFormat(av_codec_context->pix_fmt);
180 if (format != VideoFrame::YV12) {
181 LOG(ERROR) << "Cannot handle non YV12 video format: " << format;
182 continue;
184 if (video_stream_index_ != -1) {
185 LOG(WARNING) << "Found multiple video streams.";
187 video_stream_index_ = static_cast<int>(i);
188 if (override_fps > 0) {
189 // If video is played at a manual speed audio needs to match.
190 playback_rate_ = 1.0 * override_fps *
191 av_stream->r_frame_rate.den / av_stream->r_frame_rate.num;
192 video_frame_rate_numerator_ = override_fps;
193 video_frame_rate_denominator_ = 1;
194 } else {
195 playback_rate_ = 1.0;
196 video_frame_rate_numerator_ = av_stream->r_frame_rate.num;
197 video_frame_rate_denominator_ = av_stream->r_frame_rate.den;
199 LOG(INFO) << "Source file has video.";
200 } else {
201 LOG(ERROR) << "Unknown stream type; ignore.";
205 Rewind();
208 void FakeMediaSource::SetVariableFrameSizeMode(bool enabled) {
209 variable_frame_size_mode_ = enabled;
212 void FakeMediaSource::Start(scoped_refptr<AudioFrameInput> audio_frame_input,
213 scoped_refptr<VideoFrameInput> video_frame_input) {
214 audio_frame_input_ = audio_frame_input;
215 video_frame_input_ = video_frame_input;
217 LOG(INFO) << "Max Frame rate: " << video_config_.max_frame_rate;
218 LOG(INFO) << "Source Frame rate: "
219 << video_frame_rate_numerator_ << "/"
220 << video_frame_rate_denominator_ << " fps.";
221 LOG(INFO) << "Audio playback rate: " << playback_rate_;
223 if (start_time_.is_null())
224 start_time_ = clock_->NowTicks();
226 if (!is_transcoding_audio() && !is_transcoding_video()) {
227 // Send fake patterns.
228 task_runner_->PostTask(
229 FROM_HERE,
230 base::Bind(&FakeMediaSource::SendNextFakeFrame,
231 weak_factory_.GetWeakPtr()));
232 return;
235 // Send transcoding streams.
236 audio_algo_.Initialize(source_audio_params_);
237 audio_algo_.FlushBuffers();
238 audio_fifo_input_bus_ = AudioBus::Create(
239 source_audio_params_.channels(),
240 source_audio_params_.frames_per_buffer());
241 // Audio FIFO can carry all data fron AudioRendererAlgorithm.
242 audio_fifo_.reset(
243 new AudioFifo(source_audio_params_.channels(),
244 audio_algo_.QueueCapacity()));
245 audio_converter_.reset(new media::AudioConverter(
246 source_audio_params_, output_audio_params_, true));
247 audio_converter_->AddInput(this);
248 task_runner_->PostTask(
249 FROM_HERE,
250 base::Bind(&FakeMediaSource::SendNextFrame, weak_factory_.GetWeakPtr()));
253 void FakeMediaSource::SendNextFakeFrame() {
254 UpdateNextFrameSize();
255 scoped_refptr<VideoFrame> video_frame =
256 VideoFrame::CreateBlackFrame(current_frame_size_);
257 PopulateVideoFrame(video_frame.get(), synthetic_count_);
258 ++synthetic_count_;
260 const base::TimeTicks now = clock_->NowTicks();
262 base::TimeDelta video_time = VideoFrameTime(++video_frame_count_);
263 video_frame->set_timestamp(video_time);
264 if (keep_frames_)
265 inserted_video_frame_queue_.push(video_frame);
266 video_frame_input_->InsertRawVideoFrame(video_frame,
267 start_time_ + video_time);
269 // Send just enough audio data to match next video frame's time.
270 base::TimeDelta audio_time = AudioFrameTime(audio_frame_count_);
271 while (audio_time < video_time) {
272 if (is_transcoding_audio()) {
273 Decode(true);
274 CHECK(!audio_bus_queue_.empty()) << "No audio decoded.";
275 scoped_ptr<AudioBus> bus(audio_bus_queue_.front());
276 audio_bus_queue_.pop();
277 audio_frame_input_->InsertAudio(
278 bus.Pass(), start_time_ + audio_time);
279 } else {
280 audio_frame_input_->InsertAudio(
281 audio_bus_factory_->NextAudioBus(
282 base::TimeDelta::FromMilliseconds(kAudioFrameMs)),
283 start_time_ + audio_time);
285 audio_time = AudioFrameTime(++audio_frame_count_);
288 // This is the time since FakeMediaSource was started.
289 const base::TimeDelta elapsed_time = now - start_time_;
291 // Handle the case when frame generation cannot keep up.
292 // Move the time ahead to match the next frame.
293 while (video_time < elapsed_time) {
294 LOG(WARNING) << "Skipping one frame.";
295 video_time = VideoFrameTime(++video_frame_count_);
298 task_runner_->PostDelayedTask(
299 FROM_HERE,
300 base::Bind(&FakeMediaSource::SendNextFakeFrame,
301 weak_factory_.GetWeakPtr()),
302 video_time - elapsed_time);
305 void FakeMediaSource::UpdateNextFrameSize() {
306 if (variable_frame_size_mode_) {
307 bool update_size_change_time = false;
308 if (current_frame_size_.IsEmpty()) {
309 current_frame_size_ = gfx::Size(kStartingFakeFrameWidth,
310 kStartingFakeFrameHeight);
311 update_size_change_time = true;
312 } else if (clock_->NowTicks() >= next_frame_size_change_time_) {
313 current_frame_size_ = gfx::Size(
314 base::RandInt(kMinFakeFrameWidth, kMaxFakeFrameWidth),
315 base::RandInt(kMinFakeFrameHeight, kMaxFakeFrameHeight));
316 update_size_change_time = true;
319 if (update_size_change_time) {
320 next_frame_size_change_time_ = clock_->NowTicks() +
321 base::TimeDelta::FromMillisecondsD(
322 base::RandDouble() * kMaxFrameSizeChangeMillis);
324 } else {
325 current_frame_size_ = gfx::Size(kStartingFakeFrameWidth,
326 kStartingFakeFrameHeight);
327 next_frame_size_change_time_ = base::TimeTicks();
331 bool FakeMediaSource::SendNextTranscodedVideo(base::TimeDelta elapsed_time) {
332 if (!is_transcoding_video())
333 return false;
335 Decode(false);
336 if (video_frame_queue_.empty())
337 return false;
339 const scoped_refptr<VideoFrame> video_frame = video_frame_queue_.front();
340 if (elapsed_time < video_frame->timestamp())
341 return false;
342 video_frame_queue_.pop();
344 // Use the timestamp from the file if we're transcoding.
345 video_frame->set_timestamp(ScaleTimestamp(video_frame->timestamp()));
346 if (keep_frames_)
347 inserted_video_frame_queue_.push(video_frame);
348 video_frame_input_->InsertRawVideoFrame(
349 video_frame, start_time_ + video_frame->timestamp());
351 // Make sure queue is not empty.
352 Decode(false);
353 return true;
356 bool FakeMediaSource::SendNextTranscodedAudio(base::TimeDelta elapsed_time) {
357 if (!is_transcoding_audio())
358 return false;
360 Decode(true);
361 if (audio_bus_queue_.empty())
362 return false;
364 base::TimeDelta audio_time = audio_sent_ts_->GetTimestamp();
365 if (elapsed_time < audio_time)
366 return false;
367 scoped_ptr<AudioBus> bus(audio_bus_queue_.front());
368 audio_bus_queue_.pop();
369 audio_sent_ts_->AddFrames(bus->frames());
370 audio_frame_input_->InsertAudio(
371 bus.Pass(), start_time_ + audio_time);
373 // Make sure queue is not empty.
374 Decode(true);
375 return true;
378 void FakeMediaSource::SendNextFrame() {
379 // Send as much as possible. Audio is sent according to
380 // system time.
381 while (SendNextTranscodedAudio(clock_->NowTicks() - start_time_));
383 // Video is sync'ed to audio.
384 while (SendNextTranscodedVideo(audio_sent_ts_->GetTimestamp()));
386 if (audio_bus_queue_.empty() && video_frame_queue_.empty()) {
387 // Both queues are empty can only mean that we have reached
388 // the end of the stream.
389 LOG(INFO) << "Rewind.";
390 Rewind();
393 // Send next send.
394 task_runner_->PostDelayedTask(
395 FROM_HERE,
396 base::Bind(&FakeMediaSource::SendNextFrame, weak_factory_.GetWeakPtr()),
397 base::TimeDelta::FromMilliseconds(kAudioFrameMs));
400 base::TimeDelta FakeMediaSource::VideoFrameTime(int frame_number) {
401 return frame_number * base::TimeDelta::FromSeconds(1) *
402 video_frame_rate_denominator_ / video_frame_rate_numerator_;
405 base::TimeDelta FakeMediaSource::ScaleTimestamp(base::TimeDelta timestamp) {
406 return base::TimeDelta::FromSecondsD(timestamp.InSecondsF() / playback_rate_);
409 base::TimeDelta FakeMediaSource::AudioFrameTime(int frame_number) {
410 return frame_number * base::TimeDelta::FromMilliseconds(kAudioFrameMs);
413 void FakeMediaSource::Rewind() {
414 CHECK(av_seek_frame(av_format_context_, -1, 0, AVSEEK_FLAG_BACKWARD) >= 0)
415 << "Failed to rewind to the beginning.";
418 ScopedAVPacket FakeMediaSource::DemuxOnePacket(bool* audio) {
419 ScopedAVPacket packet(new AVPacket());
420 if (av_read_frame(av_format_context_, packet.get()) < 0) {
421 VLOG(1) << "Failed to read one AVPacket.";
422 packet.reset();
423 return packet.Pass();
426 int stream_index = static_cast<int>(packet->stream_index);
427 if (stream_index == audio_stream_index_) {
428 *audio = true;
429 } else if (stream_index == video_stream_index_) {
430 *audio = false;
431 } else {
432 // Ignore unknown packet.
433 LOG(INFO) << "Unknown packet.";
434 packet.reset();
436 return packet.Pass();
439 void FakeMediaSource::DecodeAudio(ScopedAVPacket packet) {
440 // Audio.
441 AVFrame* avframe = av_frame_alloc();
443 // Make a shallow copy of packet so we can slide packet.data as frames are
444 // decoded from the packet; otherwise av_free_packet() will corrupt memory.
445 AVPacket packet_temp = *packet.get();
447 do {
448 int frame_decoded = 0;
449 int result = avcodec_decode_audio4(
450 av_audio_context(), avframe, &frame_decoded, &packet_temp);
451 CHECK(result >= 0) << "Failed to decode audio.";
452 packet_temp.size -= result;
453 packet_temp.data += result;
454 if (!frame_decoded)
455 continue;
457 int frames_read = avframe->nb_samples;
458 if (frames_read < 0)
459 break;
461 if (!audio_sent_ts_) {
462 // Initialize the base time to the first packet in the file.
463 // This is set to the frequency we send to the receiver.
464 // Not the frequency of the source file. This is because we
465 // increment the frame count by samples we sent.
466 audio_sent_ts_.reset(
467 new AudioTimestampHelper(output_audio_params_.sample_rate()));
468 // For some files this is an invalid value.
469 base::TimeDelta base_ts;
470 audio_sent_ts_->SetBaseTimestamp(base_ts);
473 scoped_refptr<AudioBuffer> buffer =
474 AudioBuffer::CopyFrom(
475 AVSampleFormatToSampleFormat(
476 av_audio_context()->sample_fmt),
477 ChannelLayoutToChromeChannelLayout(
478 av_audio_context()->channel_layout,
479 av_audio_context()->channels),
480 av_audio_context()->channels,
481 av_audio_context()->sample_rate,
482 frames_read,
483 &avframe->data[0],
484 PtsToTimeDelta(avframe->pkt_pts, av_audio_stream()->time_base));
485 audio_algo_.EnqueueBuffer(buffer);
486 av_frame_unref(avframe);
487 } while (packet_temp.size > 0);
488 av_frame_free(&avframe);
490 const int frames_needed_to_scale =
491 playback_rate_ * av_audio_context()->sample_rate /
492 kAudioPacketsPerSecond;
493 while (frames_needed_to_scale <= audio_algo_.frames_buffered()) {
494 if (!audio_algo_.FillBuffer(audio_fifo_input_bus_.get(), 0,
495 audio_fifo_input_bus_->frames(),
496 playback_rate_)) {
497 // Nothing can be scaled. Decode some more.
498 return;
501 // Prevent overflow of audio data in the FIFO.
502 if (audio_fifo_input_bus_->frames() + audio_fifo_->frames()
503 <= audio_fifo_->max_frames()) {
504 audio_fifo_->Push(audio_fifo_input_bus_.get());
505 } else {
506 LOG(WARNING) << "Audio FIFO full; dropping samples.";
509 // Make sure there's enough data to resample audio.
510 if (audio_fifo_->frames() <
511 2 * source_audio_params_.sample_rate() / kAudioPacketsPerSecond) {
512 continue;
515 scoped_ptr<media::AudioBus> resampled_bus(
516 media::AudioBus::Create(
517 output_audio_params_.channels(),
518 output_audio_params_.sample_rate() / kAudioPacketsPerSecond));
519 audio_converter_->Convert(resampled_bus.get());
520 audio_bus_queue_.push(resampled_bus.release());
524 void FakeMediaSource::DecodeVideo(ScopedAVPacket packet) {
525 // Video.
526 int got_picture;
527 AVFrame* avframe = av_frame_alloc();
528 CHECK(avcodec_decode_video2(
529 av_video_context(), avframe, &got_picture, packet.get()) >= 0)
530 << "Video decode error.";
531 if (!got_picture) {
532 av_frame_free(&avframe);
533 return;
535 gfx::Size size(av_video_context()->width, av_video_context()->height);
537 if (!video_first_pts_set_) {
538 video_first_pts_ = avframe->pkt_pts;
539 video_first_pts_set_ = true;
541 const AVRational& time_base = av_video_stream()->time_base;
542 base::TimeDelta timestamp =
543 PtsToTimeDelta(avframe->pkt_pts - video_first_pts_, time_base);
544 if (timestamp < last_video_frame_timestamp_) {
545 // Stream has rewound. Rebase |video_first_pts_|.
546 const AVRational& frame_rate = av_video_stream()->r_frame_rate;
547 timestamp = last_video_frame_timestamp_ +
548 (base::TimeDelta::FromSeconds(1) * frame_rate.den / frame_rate.num);
549 const int64 adjustment_pts = TimeDeltaToPts(timestamp, time_base);
550 video_first_pts_ = avframe->pkt_pts - adjustment_pts;
553 video_frame_queue_.push(
554 VideoFrame::WrapExternalYuvData(
555 media::VideoFrame::YV12,
556 size,
557 gfx::Rect(size),
558 size,
559 avframe->linesize[0],
560 avframe->linesize[1],
561 avframe->linesize[2],
562 avframe->data[0],
563 avframe->data[1],
564 avframe->data[2],
565 timestamp,
566 base::Bind(&AVFreeFrame, avframe)));
567 last_video_frame_timestamp_ = timestamp;
570 void FakeMediaSource::Decode(bool decode_audio) {
571 // Read the stream until one video frame can be decoded.
572 while (true) {
573 if (decode_audio && !audio_bus_queue_.empty())
574 return;
575 if (!decode_audio && !video_frame_queue_.empty())
576 return;
578 bool audio_packet = false;
579 ScopedAVPacket packet = DemuxOnePacket(&audio_packet);
580 if (!packet) {
581 VLOG(1) << "End of stream.";
582 return;
585 if (audio_packet)
586 DecodeAudio(packet.Pass());
587 else
588 DecodeVideo(packet.Pass());
592 double FakeMediaSource::ProvideInput(media::AudioBus* output_bus,
593 base::TimeDelta buffer_delay) {
594 if (audio_fifo_->frames() >= output_bus->frames()) {
595 audio_fifo_->Consume(output_bus, 0, output_bus->frames());
596 return 1.0;
597 } else {
598 LOG(WARNING) << "Not enough audio data for resampling.";
599 output_bus->Zero();
600 return 0.0;
604 scoped_refptr<media::VideoFrame>
605 FakeMediaSource::PopOldestInsertedVideoFrame() {
606 CHECK(!inserted_video_frame_queue_.empty());
607 scoped_refptr<media::VideoFrame> video_frame =
608 inserted_video_frame_queue_.front();
609 inserted_video_frame_queue_.pop();
610 return video_frame;
613 AVStream* FakeMediaSource::av_audio_stream() {
614 return av_format_context_->streams[audio_stream_index_];
617 AVStream* FakeMediaSource::av_video_stream() {
618 return av_format_context_->streams[video_stream_index_];
621 AVCodecContext* FakeMediaSource::av_audio_context() {
622 return av_audio_stream()->codec;
625 AVCodecContext* FakeMediaSource::av_video_context() {
626 return av_video_stream()->codec;
629 } // namespace cast
630 } // namespace media