Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / media / cast / test / sender.cc
index e457e2c..40ca369 100644 (file)
 #include "base/at_exit.h"
 #include "base/base_paths.h"
 #include "base/command_line.h"
-#include "base/file_util.h"
 #include "base/files/file_path.h"
-#include "base/files/memory_mapped_file.h"
-#include "base/files/scoped_file.h"
 #include "base/json/json_writer.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/threading/thread.h"
 #include "base/time/default_tick_clock.h"
 #include "base/values.h"
-#include "media/audio/audio_parameters.h"
-#include "media/base/audio_buffer.h"
-#include "media/base/audio_bus.h"
-#include "media/base/audio_fifo.h"
-#include "media/base/audio_timestamp_helper.h"
 #include "media/base/media.h"
-#include "media/base/multi_channel_resampler.h"
 #include "media/base/video_frame.h"
-#include "media/base/video_util.h"
 #include "media/cast/cast_config.h"
 #include "media/cast/cast_environment.h"
 #include "media/cast/cast_sender.h"
 #include "media/cast/logging/proto/raw_events.pb.h"
 #include "media/cast/logging/receiver_time_offset_estimator_impl.h"
 #include "media/cast/logging/stats_event_subscriber.h"
-#include "media/cast/test/utility/audio_utility.h"
+#include "media/cast/net/cast_transport_defines.h"
+#include "media/cast/net/cast_transport_sender.h"
+#include "media/cast/net/udp_transport.h"
+#include "media/cast/test/fake_media_source.h"
 #include "media/cast/test/utility/default_config.h"
 #include "media/cast/test/utility/input_builder.h"
-#include "media/cast/test/utility/video_utility.h"
-#include "media/cast/transport/cast_transport_defines.h"
-#include "media/cast/transport/cast_transport_sender.h"
-#include "media/cast/transport/transport/udp_transport.h"
-#include "media/ffmpeg/ffmpeg_common.h"
-#include "media/ffmpeg/ffmpeg_deleters.h"
-#include "media/filters/audio_renderer_algorithm.h"
-#include "media/filters/ffmpeg_demuxer.h"
-#include "media/filters/ffmpeg_glue.h"
-#include "media/filters/in_memory_url_protocol.h"
-#include "ui/gfx/size.h"
 
 namespace {
 static const int kAudioChannels = 2;
 static const int kAudioSamplingFrequency = 48000;
-static const int kSoundFrequency = 1234;  // Frequency of sinusoid wave.
-static const float kSoundVolume = 0.5f;
-static const int kAudioFrameMs = 10;  // Each audio frame is exactly 10ms.
-static const int kAudioPacketsPerSecond = 1000 / kAudioFrameMs;
 
 // The max allowed size of serialized log.
 const int kMaxSerializedLogBytes = 10 * 1000 * 1000;
@@ -79,38 +57,31 @@ const int kMaxSerializedLogBytes = 10 * 1000 * 1000;
 //
 // --fps=xx
 //   Override framerate of the video stream.
-
 const char kSwitchAddress[] = "address";
 const char kSwitchPort[] = "port";
 const char kSwitchSourceFile[] = "source-file";
 const char kSwitchFps[] = "fps";
 
-}  // namespace
-
-namespace media {
-namespace cast {
-
-AudioSenderConfig GetAudioSenderConfig() {
-  AudioSenderConfig audio_config;
-
-  audio_config.rtcp_c_name = "audio_sender@a.b.c.d";
+media::cast::AudioSenderConfig GetAudioSenderConfig() {
+  media::cast::AudioSenderConfig audio_config;
 
   audio_config.use_external_encoder = false;
   audio_config.frequency = kAudioSamplingFrequency;
   audio_config.channels = kAudioChannels;
-  audio_config.bitrate = 64000;
-  audio_config.codec = transport::kOpus;
-  audio_config.rtp_config.ssrc = 1;
+  audio_config.bitrate = 0;  // Use Opus auto-VBR mode.
+  audio_config.codec = media::cast::CODEC_AUDIO_OPUS;
+  audio_config.ssrc = 1;
   audio_config.incoming_feedback_ssrc = 2;
-  audio_config.rtp_config.payload_type = 127;
-  audio_config.rtp_config.max_delay_ms = 300;
+  audio_config.rtp_payload_type = 127;
+  // TODO(miu): The default in cast_defines.h is 100.  Should this be 100, and
+  // should receiver.cc's config also be 100?
+  audio_config.target_playout_delay = base::TimeDelta::FromMilliseconds(300);
   return audio_config;
 }
 
-VideoSenderConfig GetVideoSenderConfig() {
-  VideoSenderConfig video_config;
+media::cast::VideoSenderConfig GetVideoSenderConfig() {
+  media::cast::VideoSenderConfig video_config;
 
-  video_config.rtcp_c_name = "video_sender@a.b.c.d";
   video_config.use_external_encoder = false;
 
   // Resolution.
@@ -124,7 +95,7 @@ VideoSenderConfig GetVideoSenderConfig() {
   video_config.start_bitrate = video_config.min_bitrate;
 
   // Codec.
-  video_config.codec = transport::kVp8;
+  video_config.codec = media::cast::CODEC_VIDEO_VP8;
   video_config.max_number_of_video_buffers_used = 1;
   video_config.number_of_encode_threads = 2;
 
@@ -133,626 +104,24 @@ VideoSenderConfig GetVideoSenderConfig() {
   video_config.max_qp = 40;
 
   // SSRCs and payload type. Don't change them.
-  video_config.rtp_config.ssrc = 11;
+  video_config.ssrc = 11;
   video_config.incoming_feedback_ssrc = 12;
-  video_config.rtp_config.payload_type = 96;
-  video_config.rtp_config.max_delay_ms = 300;
+  video_config.rtp_payload_type = 96;
+  // TODO(miu): The default in cast_defines.h is 100.  Should this be 100, and
+  // should receiver.cc's config also be 100?
+  video_config.target_playout_delay = base::TimeDelta::FromMilliseconds(300);
   return video_config;
 }
 
-void AVFreeFrame(AVFrame* frame) { av_frame_free(&frame); }
-
-class SendProcess {
- public:
-  SendProcess(scoped_refptr<base::SingleThreadTaskRunner> thread_proxy,
-              base::TickClock* clock,
-              const VideoSenderConfig& video_config)
-      : test_app_thread_proxy_(thread_proxy),
-        video_config_(video_config),
-        synthetic_count_(0),
-        clock_(clock),
-        audio_frame_count_(0),
-        video_frame_count_(0),
-        weak_factory_(this),
-        av_format_context_(NULL),
-        audio_stream_index_(-1),
-        playback_rate_(1.0),
-        video_stream_index_(-1),
-        video_frame_rate_numerator_(video_config.max_frame_rate),
-        video_frame_rate_denominator_(1),
-        video_first_pts_(0),
-        video_first_pts_set_(false) {
-    audio_bus_factory_.reset(new TestAudioBusFactory(kAudioChannels,
-                                                     kAudioSamplingFrequency,
-                                                     kSoundFrequency,
-                                                     kSoundVolume));
-    const CommandLine* cmd = CommandLine::ForCurrentProcess();
-    int override_fps = 0;
-    if (base::StringToInt(cmd->GetSwitchValueASCII(kSwitchFps),
-                          &override_fps)) {
-      video_config_.max_frame_rate = override_fps;
-      video_frame_rate_numerator_ = override_fps;
-    }
-
-    // Load source file and prepare FFmpeg demuxer.
-    base::FilePath source_path = cmd->GetSwitchValuePath(kSwitchSourceFile);
-    if (source_path.empty())
-      return;
-
-    LOG(INFO) << "Source: " << source_path.value();
-    if (!file_data_.Initialize(source_path)) {
-      LOG(ERROR) << "Cannot load file.";
-      return;
-    }
-    protocol_.reset(
-        new InMemoryUrlProtocol(file_data_.data(), file_data_.length(), false));
-    glue_.reset(new FFmpegGlue(protocol_.get()));
-
-    if (!glue_->OpenContext()) {
-      LOG(ERROR) << "Cannot open file.";
-      return;
-    }
-
-    // AVFormatContext is owned by the glue.
-    av_format_context_ = glue_->format_context();
-    if (avformat_find_stream_info(av_format_context_, NULL) < 0) {
-      LOG(ERROR) << "Cannot find stream information.";
-      return;
-    }
-
-    // Prepare FFmpeg decoders.
-    for (unsigned int i = 0; i < av_format_context_->nb_streams; ++i) {
-      AVStream* av_stream = av_format_context_->streams[i];
-      AVCodecContext* av_codec_context = av_stream->codec;
-      AVCodec* av_codec = avcodec_find_decoder(av_codec_context->codec_id);
-
-      if (!av_codec) {
-        LOG(ERROR) << "Cannot find decoder for the codec: "
-                   << av_codec_context->codec_id;
-        continue;
-      }
-
-      // Number of threads for decoding.
-      av_codec_context->thread_count = 2;
-      av_codec_context->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
-      av_codec_context->request_sample_fmt = AV_SAMPLE_FMT_S16;
-
-      if (avcodec_open2(av_codec_context, av_codec, NULL) < 0) {
-        LOG(ERROR) << "Cannot open AVCodecContext for the codec: "
-                   << av_codec_context->codec_id;
-        return;
-      }
-
-      if (av_codec->type == AVMEDIA_TYPE_AUDIO) {
-        if (av_codec_context->sample_fmt == AV_SAMPLE_FMT_S16P) {
-          LOG(ERROR) << "Audio format not supported.";
-          continue;
-        }
-        ChannelLayout layout = ChannelLayoutToChromeChannelLayout(
-            av_codec_context->channel_layout,
-            av_codec_context->channels);
-        if (layout == CHANNEL_LAYOUT_UNSUPPORTED) {
-          LOG(ERROR) << "Unsupported audio channels layout.";
-          continue;
-        }
-        if (audio_stream_index_ != -1) {
-          LOG(WARNING) << "Found multiple audio streams.";
-        }
-        audio_stream_index_ = static_cast<int>(i);
-        audio_params_.Reset(
-            AudioParameters::AUDIO_PCM_LINEAR,
-            layout,
-            av_codec_context->channels,
-            av_codec_context->channels,
-            av_codec_context->sample_rate,
-            8 * av_get_bytes_per_sample(av_codec_context->sample_fmt),
-            av_codec_context->sample_rate / kAudioPacketsPerSecond);
-        LOG(INFO) << "Source file has audio.";
-      } else if (av_codec->type == AVMEDIA_TYPE_VIDEO) {
-        VideoFrame::Format format =
-            PixelFormatToVideoFormat(av_codec_context->pix_fmt);
-        if (format != VideoFrame::YV12) {
-          LOG(ERROR) << "Cannot handle non YV12 video format: " << format;
-          continue;
-        }
-        if (video_stream_index_ != -1) {
-          LOG(WARNING) << "Found multiple video streams.";
-        }
-        video_stream_index_ = static_cast<int>(i);
-        if (!override_fps) {
-          video_frame_rate_numerator_ = av_stream->r_frame_rate.num;
-          video_frame_rate_denominator_ = av_stream->r_frame_rate.den;
-          // Max frame rate is rounded up.
-          video_config_.max_frame_rate =
-              video_frame_rate_denominator_ +
-              video_frame_rate_numerator_ - 1;
-          video_config_.max_frame_rate /= video_frame_rate_denominator_;
-        } else {
-          // If video is played at a manual speed audio needs to match.
-          playback_rate_ = 1.0 * override_fps *
-               av_stream->r_frame_rate.den /  av_stream->r_frame_rate.num;
-        }
-        LOG(INFO) << "Source file has video.";
-      } else {
-        LOG(ERROR) << "Unknown stream type; ignore.";
-      }
-    }
-
-    Rewind();
-  }
-
-  ~SendProcess() {
-  }
-
-  void Start(scoped_refptr<AudioFrameInput> audio_frame_input,
-             scoped_refptr<VideoFrameInput> video_frame_input) {
-    audio_frame_input_ = audio_frame_input;
-    video_frame_input_ = video_frame_input;
-
-    LOG(INFO) << "Max Frame rate: " << video_config_.max_frame_rate;
-    LOG(INFO) << "Real Frame rate: "
-              << video_frame_rate_numerator_ << "/"
-              << video_frame_rate_denominator_ << " fps.";
-    LOG(INFO) << "Audio playback rate: " << playback_rate_;
-
-    if (!is_transcoding_audio() && !is_transcoding_video()) {
-      // Send fake patterns.
-      test_app_thread_proxy_->PostTask(
-          FROM_HERE,
-          base::Bind(
-              &SendProcess::SendNextFakeFrame,
-              base::Unretained(this)));
-      return;
-    }
-
-    // Send transcoding streams.
-    audio_algo_.Initialize(playback_rate_, audio_params_);
-    audio_algo_.FlushBuffers();
-    audio_fifo_input_bus_ =
-        AudioBus::Create(
-            audio_params_.channels(), audio_params_.frames_per_buffer());
-    // Audio FIFO can carry all data fron AudioRendererAlgorithm.
-    audio_fifo_.reset(
-        new AudioFifo(audio_params_.channels(),
-                      audio_algo_.QueueCapacity()));
-    audio_resampler_.reset(new media::MultiChannelResampler(
-        audio_params_.channels(),
-        static_cast<double>(audio_params_.sample_rate()) /
-        kAudioSamplingFrequency,
-        audio_params_.frames_per_buffer(),
-        base::Bind(&SendProcess::ProvideData, base::Unretained(this))));
-    test_app_thread_proxy_->PostTask(
-        FROM_HERE,
-        base::Bind(
-            &SendProcess::SendNextFrame,
-            base::Unretained(this)));
-  }
-
-  void SendNextFakeFrame() {
-    gfx::Size size(video_config_.width, video_config_.height);
-    scoped_refptr<VideoFrame> video_frame =
-        VideoFrame::CreateBlackFrame(size);
-    PopulateVideoFrame(video_frame, synthetic_count_);
-    ++synthetic_count_;
-
-    base::TimeTicks now = clock_->NowTicks();
-    if (start_time_.is_null())
-      start_time_ = now;
-
-    base::TimeDelta video_time = VideoFrameTime(video_frame_count_);
-    video_frame->set_timestamp(video_time);
-    video_frame_input_->InsertRawVideoFrame(video_frame,
-                                            start_time_ + video_time);
-
-    // Send just enough audio data to match next video frame's time.
-    base::TimeDelta audio_time = AudioFrameTime(audio_frame_count_);
-    while (audio_time < video_time) {
-      if (is_transcoding_audio()) {
-        Decode(true);
-        CHECK(!audio_bus_queue_.empty()) << "No audio decoded.";
-        scoped_ptr<AudioBus> bus(audio_bus_queue_.front());
-        audio_bus_queue_.pop();
-        audio_frame_input_->InsertAudio(
-            bus.Pass(), start_time_ + audio_time);
-      } else {
-        audio_frame_input_->InsertAudio(
-            audio_bus_factory_->NextAudioBus(
-                base::TimeDelta::FromMilliseconds(kAudioFrameMs)),
-            start_time_ + audio_time);
-      }
-      audio_time = AudioFrameTime(++audio_frame_count_);
-    }
-
-    // This is the time since the stream started.
-    const base::TimeDelta elapsed_time = now - start_time_;
-
-    // Handle the case when frame generation cannot keep up.
-    // Move the time ahead to match the next frame.
-    while (video_time < elapsed_time) {
-      LOG(WARNING) << "Skipping one frame.";
-      video_time = VideoFrameTime(++video_frame_count_);
-    }
-
-    test_app_thread_proxy_->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&SendProcess::SendNextFakeFrame,
-                   weak_factory_.GetWeakPtr()),
-        video_time - elapsed_time);
-  }
-
-  // Return true if a frame was sent.
-  bool SendNextTranscodedVideo(base::TimeDelta elapsed_time) {
-    if (!is_transcoding_video())
-      return false;
-
-    Decode(false);
-    if (video_frame_queue_.empty())
-      return false;
-
-    scoped_refptr<VideoFrame> decoded_frame =
-        video_frame_queue_.front();
-    if (elapsed_time < decoded_frame->timestamp())
-      return false;
-
-    gfx::Size size(video_config_.width, video_config_.height);
-    scoped_refptr<VideoFrame> video_frame =
-        VideoFrame::CreateBlackFrame(size);
-    video_frame_queue_.pop();
-    media::CopyPlane(VideoFrame::kYPlane,
-                     decoded_frame->data(VideoFrame::kYPlane),
-                     decoded_frame->stride(VideoFrame::kYPlane),
-                     decoded_frame->rows(VideoFrame::kYPlane),
-                     video_frame);
-    media::CopyPlane(VideoFrame::kUPlane,
-                     decoded_frame->data(VideoFrame::kUPlane),
-                     decoded_frame->stride(VideoFrame::kUPlane),
-                     decoded_frame->rows(VideoFrame::kUPlane),
-                     video_frame);
-    media::CopyPlane(VideoFrame::kVPlane,
-                     decoded_frame->data(VideoFrame::kVPlane),
-                     decoded_frame->stride(VideoFrame::kVPlane),
-                     decoded_frame->rows(VideoFrame::kVPlane),
-                     video_frame);
-
-    base::TimeDelta video_time;
-    // Use the timestamp from the file if we're transcoding.
-    video_time = ScaleTimestamp(decoded_frame->timestamp());
-    video_frame_input_->InsertRawVideoFrame(
-        video_frame, start_time_ + video_time);
-
-    // Make sure queue is not empty.
-    Decode(false);
-    return true;
-  }
-
-  // Return true if a frame was sent.
-  bool SendNextTranscodedAudio(base::TimeDelta elapsed_time) {
-    if (!is_transcoding_audio())
-      return false;
-
-    Decode(true);
-    if (audio_bus_queue_.empty())
-      return false;
-
-    base::TimeDelta audio_time = audio_sent_ts_->GetTimestamp();
-    if (elapsed_time < audio_time)
-      return false;
-    scoped_ptr<AudioBus> bus(audio_bus_queue_.front());
-    audio_bus_queue_.pop();
-    audio_sent_ts_->AddFrames(bus->frames());
-    audio_frame_input_->InsertAudio(
-        bus.Pass(), start_time_ + audio_time);
-
-    // Make sure queue is not empty.
-    Decode(true);
-    return true;
-  }
-
-  void SendNextFrame() {
-    if (start_time_.is_null())
-      start_time_ = clock_->NowTicks();
-    if (start_time_.is_null())
-      start_time_ = clock_->NowTicks();
-
-    // Send as much as possible. Audio is sent according to
-    // system time.
-    while (SendNextTranscodedAudio(clock_->NowTicks() - start_time_));
-
-    // Video is sync'ed to audio.
-    while (SendNextTranscodedVideo(audio_sent_ts_->GetTimestamp()));
-
-    if (audio_bus_queue_.empty() && video_frame_queue_.empty()) {
-      // Both queues are empty can only mean that we have reached
-      // the end of the stream.
-      LOG(INFO) << "Rewind.";
-      Rewind();
-      start_time_ = base::TimeTicks();
-      audio_sent_ts_.reset();
-      video_first_pts_set_ = false;
-    }
-
-    // Send next send.
-    test_app_thread_proxy_->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(
-            &SendProcess::SendNextFrame,
-            base::Unretained(this)),
-        base::TimeDelta::FromMilliseconds(kAudioFrameMs));
-  }
-
-  const VideoSenderConfig& get_video_config() const { return video_config_; }
-
- private:
-  bool is_transcoding_audio() { return audio_stream_index_ >= 0; }
-  bool is_transcoding_video() { return video_stream_index_ >= 0; }
-
-  // Helper methods to compute timestamps for the frame number specified.
-  base::TimeDelta VideoFrameTime(int frame_number) {
-    return frame_number * base::TimeDelta::FromSeconds(1) *
-        video_frame_rate_denominator_ / video_frame_rate_numerator_;
-  }
-
-  base::TimeDelta ScaleTimestamp(base::TimeDelta timestamp) {
-    return base::TimeDelta::FromMicroseconds(
-        timestamp.InMicroseconds() / playback_rate_);
-  }
-
-  base::TimeDelta AudioFrameTime(int frame_number) {
-    return frame_number * base::TimeDelta::FromMilliseconds(kAudioFrameMs);
-  }
-
-  // Go to the beginning of the stream.
-  void Rewind() {
-    CHECK(av_seek_frame(av_format_context_, -1, 0, AVSEEK_FLAG_BACKWARD) >= 0)
-        << "Failed to rewind to the beginning.";
-  }
-
-  // Call FFmpeg to fetch one packet.
-  ScopedAVPacket DemuxOnePacket(bool* audio) {
-    ScopedAVPacket packet(new AVPacket());
-    if (av_read_frame(av_format_context_, packet.get()) < 0) {
-      LOG(ERROR) << "Failed to read one AVPacket.";
-      packet.reset();
-      return packet.Pass();
-    }
-
-    int stream_index = static_cast<int>(packet->stream_index);
-    if (stream_index == audio_stream_index_) {
-      *audio = true;
-    } else if (stream_index == video_stream_index_) {
-      *audio = false;
-    } else {
-      // Ignore unknown packet.
-      LOG(INFO) << "Unknown packet.";
-      packet.reset();
-    }
-    return packet.Pass();
-  }
-
-  void DecodeAudio(ScopedAVPacket packet) {
-    // Audio.
-    AVFrame* avframe = av_frame_alloc();
-
-    // Make a shallow copy of packet so we can slide packet.data as frames are
-    // decoded from the packet; otherwise av_free_packet() will corrupt memory.
-    AVPacket packet_temp = *packet.get();
-
-    do {
-      int frame_decoded = 0;
-      int result = avcodec_decode_audio4(
-          av_audio_context(), avframe, &frame_decoded, &packet_temp);
-      CHECK(result >= 0) << "Failed to decode audio.";
-      packet_temp.size -= result;
-      packet_temp.data += result;
-      if (!frame_decoded)
-        continue;
-
-      int frames_read = avframe->nb_samples;
-      if (frames_read < 0)
-        break;
-
-      if (!audio_sent_ts_) {
-        // Initialize the base time to the first packet in the file.
-        // This is set to the frequency we send to the receiver.
-        // Not the frequency of the source file. This is because we
-        // increment the frame count by samples we sent.
-        audio_sent_ts_.reset(
-            new AudioTimestampHelper(kAudioSamplingFrequency));
-        // For some files this is an invalid value.
-        base::TimeDelta base_ts;
-        audio_sent_ts_->SetBaseTimestamp(base_ts);
-      }
-
-      scoped_refptr<AudioBuffer> buffer =
-          AudioBuffer::CopyFrom(
-              AVSampleFormatToSampleFormat(
-                  av_audio_context()->sample_fmt),
-              ChannelLayoutToChromeChannelLayout(
-                  av_audio_context()->channel_layout,
-                  av_audio_context()->channels),
-              av_audio_context()->channels,
-              av_audio_context()->sample_rate,
-              frames_read,
-              &avframe->data[0],
-              // Note: Not all files have correct values for pkt_pts.
-              base::TimeDelta::FromMilliseconds(avframe->pkt_pts));
-      audio_algo_.EnqueueBuffer(buffer);
-      av_frame_unref(avframe);
-    } while (packet_temp.size > 0);
-    av_frame_free(&avframe);
-
-    const int frames_needed_to_scale =
-        playback_rate_ * av_audio_context()->sample_rate /
-        kAudioPacketsPerSecond;
-    while (frames_needed_to_scale <= audio_algo_.frames_buffered()) {
-      if (!audio_algo_.FillBuffer(audio_fifo_input_bus_.get(),
-                                  audio_fifo_input_bus_->frames())) {
-        // Nothing can be scaled. Decode some more.
-        return;
-      }
-
-      // Prevent overflow of audio data in the FIFO.
-      if (audio_fifo_input_bus_->frames() + audio_fifo_->frames()
-          <= audio_fifo_->max_frames()) {
-        audio_fifo_->Push(audio_fifo_input_bus_.get());
-      } else {
-        LOG(WARNING) << "Audio FIFO full; dropping samples.";
-      }
-
-      // Make sure there's enough data to resample audio.
-      if (audio_fifo_->frames() <
-          2 * audio_params_.sample_rate() / kAudioPacketsPerSecond) {
-        continue;
-      }
-
-      scoped_ptr<media::AudioBus> resampled_bus(
-          media::AudioBus::Create(
-              audio_params_.channels(),
-              kAudioSamplingFrequency / kAudioPacketsPerSecond));
-      audio_resampler_->Resample(resampled_bus->frames(),
-                                 resampled_bus.get());
-      audio_bus_queue_.push(resampled_bus.release());
-    }
-  }
-
-  void DecodeVideo(ScopedAVPacket packet) {
-    // Video.
-    int got_picture;
-    AVFrame* avframe = av_frame_alloc();
-    // Tell the decoder to reorder for us.
-    avframe->reordered_opaque =
-        av_video_context()->reordered_opaque = packet->pts;
-    CHECK(avcodec_decode_video2(
-        av_video_context(), avframe, &got_picture, packet.get()) >= 0)
-        << "Video decode error.";
-    if (!got_picture) {
-      av_frame_free(&avframe);
-      return;
-    }
-    gfx::Size size(av_video_context()->width, av_video_context()->height);
-    if (!video_first_pts_set_ ||
-        avframe->reordered_opaque < video_first_pts_) {
-      video_first_pts_set_ = true;
-      video_first_pts_ = avframe->reordered_opaque;
-    }
-    int64 pts = avframe->reordered_opaque - video_first_pts_;
-    video_frame_queue_.push(
-        VideoFrame::WrapExternalYuvData(
-            media::VideoFrame::YV12,
-            size,
-            gfx::Rect(size),
-            size,
-            avframe->linesize[0],
-            avframe->linesize[1],
-            avframe->linesize[2],
-            avframe->data[0],
-            avframe->data[1],
-            avframe->data[2],
-            base::TimeDelta::FromMilliseconds(pts),
-            base::Bind(&AVFreeFrame, avframe)));
-  }
-
-  void Decode(bool decode_audio) {
-    // Read the stream until one video frame can be decoded.
-    while (true) {
-      if (decode_audio && !audio_bus_queue_.empty())
-        return;
-      if (!decode_audio && !video_frame_queue_.empty())
-        return;
-
-      bool audio_packet = false;
-      ScopedAVPacket packet = DemuxOnePacket(&audio_packet);
-      if (!packet) {
-        LOG(INFO) << "End of stream.";
-        return;
-      }
-
-      if (audio_packet)
-        DecodeAudio(packet.Pass());
-      else
-        DecodeVideo(packet.Pass());
-    }
-  }
-
-  void ProvideData(int frame_delay, media::AudioBus* output_bus) {
-    if (audio_fifo_->frames() >= output_bus->frames()) {
-      audio_fifo_->Consume(output_bus, 0, output_bus->frames());
-    } else {
-      LOG(WARNING) << "Not enough audio data for resampling.";
-      output_bus->Zero();
-    }
-  }
-
-  AVStream* av_audio_stream() {
-    return av_format_context_->streams[audio_stream_index_];
-  }
-  AVStream* av_video_stream() {
-    return av_format_context_->streams[video_stream_index_];
-  }
-  AVCodecContext* av_audio_context() { return av_audio_stream()->codec; }
-  AVCodecContext* av_video_context() { return av_video_stream()->codec; }
-
-  scoped_refptr<base::SingleThreadTaskRunner> test_app_thread_proxy_;
-  VideoSenderConfig video_config_;
-  scoped_refptr<AudioFrameInput> audio_frame_input_;
-  scoped_refptr<VideoFrameInput> video_frame_input_;
-  uint8 synthetic_count_;
-  base::TickClock* const clock_;  // Not owned by this class.
-
-  // Time when the stream starts.
-  base::TimeTicks start_time_;
-
-  // The following three members are used only for fake frames.
-  int audio_frame_count_;  // Each audio frame is exactly 10ms.
-  int video_frame_count_;
-  scoped_ptr<TestAudioBusFactory> audio_bus_factory_;
-
-  // NOTE: Weak pointers must be invalidated before all other member variables.
-  base::WeakPtrFactory<SendProcess> weak_factory_;
-
-  base::MemoryMappedFile file_data_;
-  scoped_ptr<InMemoryUrlProtocol> protocol_;
-  scoped_ptr<FFmpegGlue> glue_;
-  AVFormatContext* av_format_context_;
-
-  int audio_stream_index_;
-  AudioParameters audio_params_;
-  double playback_rate_;
-
-  int video_stream_index_;
-  int video_frame_rate_numerator_;
-  int video_frame_rate_denominator_;
-
-  // These are used for audio resampling.
-  scoped_ptr<media::MultiChannelResampler> audio_resampler_;
-  scoped_ptr<media::AudioFifo> audio_fifo_;
-  scoped_ptr<media::AudioBus> audio_fifo_input_bus_;
-  media::AudioRendererAlgorithm audio_algo_;
-
-  // Track the timestamp of audio sent to the receiver.
-  scoped_ptr<media::AudioTimestampHelper> audio_sent_ts_;
-
-  std::queue<scoped_refptr<VideoFrame> > video_frame_queue_;
-  int64 video_first_pts_;
-  bool video_first_pts_set_;
-
-  std::queue<AudioBus*> audio_bus_queue_;
-
-  DISALLOW_COPY_AND_ASSIGN(SendProcess);
-};
-
-}  // namespace cast
-}  // namespace media
-
-namespace {
 void UpdateCastTransportStatus(
-    media::cast::transport::CastTransportStatus status) {
+    media::cast::CastTransportStatus status) {
   VLOG(1) << "Transport status: " << status;
 }
 
 void LogRawEvents(
     const scoped_refptr<media::cast::CastEnvironment>& cast_environment,
-    const std::vector<media::cast::PacketEvent>& packet_events) {
+    const std::vector<media::cast::PacketEvent>& packet_events,
+    const std::vector<media::cast::FrameEvent>& frame_events) {
   VLOG(1) << "Got packet events from transport, size: " << packet_events.size();
   for (std::vector<media::cast::PacketEvent>::const_iterator it =
            packet_events.begin();
@@ -767,6 +136,17 @@ void LogRawEvents(
                                                    it->max_packet_id,
                                                    it->size);
   }
+  VLOG(1) << "Got frame events from transport, size: " << frame_events.size();
+  for (std::vector<media::cast::FrameEvent>::const_iterator it =
+           frame_events.begin();
+       it != frame_events.end();
+       ++it) {
+    cast_environment->Logging()->InsertFrameEvent(it->timestamp,
+                                                  it->type,
+                                                  it->media_type,
+                                                  it->rtp_timestamp,
+                                                  it->frame_id);
+  }
 }
 
 void InitializationResult(media::cast::CastInitializationStatus result) {
@@ -902,10 +282,8 @@ int main(int argc, char** argv) {
   LOG(INFO) << "Sending to " << remote_ip_address << ":" << remote_port
             << ".";
 
-  media::cast::AudioSenderConfig audio_config =
-      media::cast::GetAudioSenderConfig();
-  media::cast::VideoSenderConfig video_config =
-      media::cast::GetVideoSenderConfig();
+  media::cast::AudioSenderConfig audio_config = GetAudioSenderConfig();
+  media::cast::VideoSenderConfig video_config = GetVideoSenderConfig();
 
   // Running transport on the main thread.
   // Setting up transport config.
@@ -922,14 +300,25 @@ int main(int argc, char** argv) {
           video_thread.message_loop_proxy()));
 
   // SendProcess initialization.
-  scoped_ptr<media::cast::SendProcess> send_process(
-      new media::cast::SendProcess(test_thread.message_loop_proxy(),
-                                   cast_environment->Clock(),
-                                   video_config));
+  scoped_ptr<media::cast::FakeMediaSource> fake_media_source(
+      new media::cast::FakeMediaSource(test_thread.message_loop_proxy(),
+                                       cast_environment->Clock(),
+                                       video_config));
+
+  int override_fps = 0;
+  if (!base::StringToInt(cmd->GetSwitchValueASCII(kSwitchFps),
+                         &override_fps)){
+    override_fps = 0;
+  }
+  base::FilePath source_path = cmd->GetSwitchValuePath(kSwitchSourceFile);
+  if (!source_path.empty()) {
+    LOG(INFO) << "Source: " << source_path.value();
+    fake_media_source->SetSourceFile(source_path, override_fps);
+  }
 
   // CastTransportSender initialization.
-  scoped_ptr<media::cast::transport::CastTransportSender> transport_sender =
-      media::cast::transport::CastTransportSender::Create(
+  scoped_ptr<media::cast::CastTransportSender> transport_sender =
+      media::cast::CastTransportSender::Create(
           NULL,  // net log.
           cast_environment->Clock(),
           remote_endpoint,
@@ -942,12 +331,11 @@ int main(int argc, char** argv) {
   scoped_ptr<media::cast::CastSender> cast_sender =
       media::cast::CastSender::Create(cast_environment, transport_sender.get());
   cast_sender->InitializeVideo(
-      send_process->get_video_config(),
+      fake_media_source->get_video_config(),
       base::Bind(&InitializationResult),
       media::cast::CreateDefaultVideoEncodeAcceleratorCallback(),
       media::cast::CreateDefaultVideoEncodeMemoryCallback());
   cast_sender->InitializeAudio(audio_config, base::Bind(&InitializationResult));
-  transport_sender->SetPacketReceiver(cast_sender->packet_receiver());
 
   // Set up event subscribers.
   scoped_ptr<media::cast::EncodingEventSubscriber> video_event_subscriber;
@@ -1014,8 +402,8 @@ int main(int argc, char** argv) {
                  base::Passed(&offset_estimator)),
       base::TimeDelta::FromSeconds(logging_duration_seconds));
 
-  send_process->Start(cast_sender->audio_frame_input(),
-                      cast_sender->video_frame_input());
+  fake_media_source->Start(cast_sender->audio_frame_input(),
+                           cast_sender->video_frame_input());
 
   io_message_loop.Run();
   return 0;