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.
4
5#include "media/cast/video_sender/video_encoder_impl.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/callback.h"
10#include "base/logging.h"
11#include "base/message_loop/message_loop.h"
12#include "media/base/video_frame.h"
13#include "media/cast/cast_defines.h"
14#include "media/cast/video_sender/codecs/vp8/vp8_encoder.h"
15#include "media/cast/video_sender/fake_software_video_encoder.h"
16
17namespace media {
18namespace cast {
19
20namespace {
21
22typedef base::Callback<void(Vp8Encoder*)> PassEncoderCallback;
23
24void InitializeEncoderOnEncoderThread(
25    const scoped_refptr<CastEnvironment>& environment,
26    SoftwareVideoEncoder* encoder) {
27  DCHECK(environment->CurrentlyOn(CastEnvironment::VIDEO));
28  encoder->Initialize();
29}
30
31void EncodeVideoFrameOnEncoderThread(
32    scoped_refptr<CastEnvironment> environment,
33    SoftwareVideoEncoder* encoder,
34    const scoped_refptr<media::VideoFrame>& video_frame,
35    const base::TimeTicks& capture_time,
36    const VideoEncoderImpl::CodecDynamicConfig& dynamic_config,
37    const VideoEncoderImpl::FrameEncodedCallback& frame_encoded_callback) {
38  DCHECK(environment->CurrentlyOn(CastEnvironment::VIDEO));
39  if (dynamic_config.key_frame_requested) {
40    encoder->GenerateKeyFrame();
41  }
42  encoder->LatestFrameIdToReference(
43      dynamic_config.latest_frame_id_to_reference);
44  encoder->UpdateRates(dynamic_config.bit_rate);
45
46  scoped_ptr<transport::EncodedFrame> encoded_frame(
47      new transport::EncodedFrame());
48  if (!encoder->Encode(video_frame, encoded_frame.get())) {
49    VLOG(1) << "Encoding failed";
50    return;
51  }
52  if (encoded_frame->data.empty()) {
53    VLOG(1) << "Encoding resulted in an empty frame";
54    return;
55  }
56  encoded_frame->rtp_timestamp = transport::GetVideoRtpTimestamp(capture_time);
57  encoded_frame->reference_time = capture_time;
58
59  environment->PostTask(
60      CastEnvironment::MAIN,
61      FROM_HERE,
62      base::Bind(
63          frame_encoded_callback, base::Passed(&encoded_frame)));
64}
65}  // namespace
66
67VideoEncoderImpl::VideoEncoderImpl(
68    scoped_refptr<CastEnvironment> cast_environment,
69    const VideoSenderConfig& video_config,
70    int max_unacked_frames)
71    : video_config_(video_config),
72      cast_environment_(cast_environment) {
73  if (video_config.codec == transport::kVp8) {
74    encoder_.reset(new Vp8Encoder(video_config, max_unacked_frames));
75    cast_environment_->PostTask(CastEnvironment::VIDEO,
76                                FROM_HERE,
77                                base::Bind(&InitializeEncoderOnEncoderThread,
78                                           cast_environment,
79                                           encoder_.get()));
80#ifndef OFFICIAL_BUILD
81  } else if (video_config.codec == transport::kFakeSoftwareVideo) {
82    encoder_.reset(new FakeSoftwareVideoEncoder(video_config));
83#endif
84  } else {
85    DCHECK(false) << "Invalid config";  // Codec not supported.
86  }
87
88  dynamic_config_.key_frame_requested = false;
89  dynamic_config_.latest_frame_id_to_reference = kStartFrameId;
90  dynamic_config_.bit_rate = video_config.start_bitrate;
91}
92
93VideoEncoderImpl::~VideoEncoderImpl() {
94  DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
95  if (encoder_) {
96    cast_environment_->PostTask(
97        CastEnvironment::VIDEO,
98        FROM_HERE,
99        base::Bind(&base::DeletePointer<SoftwareVideoEncoder>,
100                   encoder_.release()));
101  }
102}
103
104bool VideoEncoderImpl::EncodeVideoFrame(
105    const scoped_refptr<media::VideoFrame>& video_frame,
106    const base::TimeTicks& capture_time,
107    const FrameEncodedCallback& frame_encoded_callback) {
108  DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
109  cast_environment_->PostTask(CastEnvironment::VIDEO,
110                              FROM_HERE,
111                              base::Bind(&EncodeVideoFrameOnEncoderThread,
112                                         cast_environment_,
113                                         encoder_.get(),
114                                         video_frame,
115                                         capture_time,
116                                         dynamic_config_,
117                                         frame_encoded_callback));
118
119  dynamic_config_.key_frame_requested = false;
120  return true;
121}
122
123// Inform the encoder about the new target bit rate.
124void VideoEncoderImpl::SetBitRate(int new_bit_rate) {
125  dynamic_config_.bit_rate = new_bit_rate;
126}
127
128// Inform the encoder to encode the next frame as a key frame.
129void VideoEncoderImpl::GenerateKeyFrame() {
130  dynamic_config_.key_frame_requested = true;
131}
132
133// Inform the encoder to only reference frames older or equal to frame_id;
134void VideoEncoderImpl::LatestFrameIdToReference(uint32 frame_id) {
135  dynamic_config_.latest_frame_id_to_reference = frame_id;
136}
137
138}  //  namespace cast
139}  //  namespace media
140