blob: f6bcb643fdc09163b153c926cf9de578d32270be [file] [log] [blame]
[email protected]f2d6a0032011-11-17 00:48:121// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]14fd1a602010-11-03 04:17:092// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "remoting/protocol/rtp_video_writer.h"
6
[email protected]182ec8f22011-08-11 02:14:357#include "base/bind.h"
[email protected]c56acf54ff2010-11-19 23:44:458#include "base/task.h"
[email protected]b3c03402010-11-16 01:27:469#include "net/base/io_buffer.h"
10#include "remoting/base/compound_buffer.h"
[email protected]182ec8f22011-08-11 02:14:3511#include "remoting/base/constants.h"
[email protected]3adf1b22010-11-09 23:22:2012#include "remoting/proto/video.pb.h"
[email protected]14fd1a602010-11-03 04:17:0913#include "remoting/protocol/rtp_writer.h"
[email protected]b3c03402010-11-16 01:27:4614#include "remoting/protocol/session.h"
[email protected]14fd1a602010-11-03 04:17:0915
16namespace remoting {
[email protected]d87c4042010-11-04 00:46:0117namespace protocol {
[email protected]14fd1a602010-11-03 04:17:0918
[email protected]6357e602010-11-16 01:53:0719namespace {
20const int kMtu = 1200;
21} // namespace
22
[email protected]60fc96002011-08-12 23:07:0523RtpVideoWriter::RtpVideoWriter(base::MessageLoopProxy* message_loop)
[email protected]f2d6a0032011-11-17 00:48:1224 : session_(NULL),
25 initialized_(false),
[email protected]60fc96002011-08-12 23:07:0526 rtp_writer_(message_loop) {
[email protected]182ec8f22011-08-11 02:14:3527}
[email protected]14fd1a602010-11-03 04:17:0928
[email protected]86dbc722011-06-30 23:23:3029RtpVideoWriter::~RtpVideoWriter() {
30 Close();
31}
[email protected]14fd1a602010-11-03 04:17:0932
[email protected]182ec8f22011-08-11 02:14:3533void RtpVideoWriter::Init(protocol::Session* session,
34 const InitializedCallback& callback) {
[email protected]f2d6a0032011-11-17 00:48:1235 session_ = session;
[email protected]182ec8f22011-08-11 02:14:3536 initialized_callback_ = callback;
37 session->CreateDatagramChannel(
38 kVideoRtpChannelName,
[email protected]dee7ab52011-08-11 02:51:3439 base::Bind(&RtpVideoWriter::OnChannelReady,
40 base::Unretained(this), true));
[email protected]182ec8f22011-08-11 02:14:3541 session->CreateDatagramChannel(
42 kVideoRtcpChannelName,
[email protected]dee7ab52011-08-11 02:51:3443 base::Bind(&RtpVideoWriter::OnChannelReady,
44 base::Unretained(this), false));
[email protected]182ec8f22011-08-11 02:14:3545}
46
[email protected]dee7ab52011-08-11 02:51:3447void RtpVideoWriter::OnChannelReady(bool rtp, net::Socket* socket) {
[email protected]182ec8f22011-08-11 02:14:3548 if (!socket) {
49 if (!initialized_) {
50 initialized_ = true;
51 initialized_callback_.Run(false);
52 }
53 return;
54 }
55
[email protected]dee7ab52011-08-11 02:51:3456 if (rtp) {
[email protected]182ec8f22011-08-11 02:14:3557 DCHECK(!rtp_channel_.get());
58 rtp_channel_.reset(socket);
59 rtp_writer_.Init(socket);
[email protected]dee7ab52011-08-11 02:51:3460 } else {
[email protected]182ec8f22011-08-11 02:14:3561 DCHECK(!rtcp_channel_.get());
62 rtcp_channel_.reset(socket);
63 // TODO(sergeyu): Use RTCP channel somehow.
64 }
65
66 if (rtp_channel_.get() && rtcp_channel_.get()) {
67 DCHECK(!initialized_);
68 initialized_ = true;
69 initialized_callback_.Run(true);
70 }
[email protected]14fd1a602010-11-03 04:17:0971}
72
[email protected]86dbc722011-06-30 23:23:3073void RtpVideoWriter::Close() {
74 rtp_writer_.Close();
[email protected]182ec8f22011-08-11 02:14:3575 rtp_channel_.reset();
76 rtcp_channel_.reset();
[email protected]f2d6a0032011-11-17 00:48:1277 if (session_) {
78 session_->CancelChannelCreation(kVideoRtpChannelName);
79 session_->CancelChannelCreation(kVideoRtcpChannelName);
80 session_ = NULL;
81 }
[email protected]86dbc722011-06-30 23:23:3082}
83
[email protected]2e8b52c2011-11-22 00:07:1384bool RtpVideoWriter::is_connected() {
85 return rtp_channel_.get() && rtcp_channel_.get();
86}
87
[email protected]9e2a3132011-10-07 05:07:4088void RtpVideoWriter::ProcessVideoPacket(const VideoPacket* packet,
89 const base::Closure& done) {
[email protected]c56acf54ff2010-11-19 23:44:4590 CHECK(packet->format().encoding() == VideoPacketFormat::ENCODING_VP8)
[email protected]6357e602010-11-16 01:53:0791 << "Only VP8 is supported in RTP.";
92
[email protected]b3c03402010-11-16 01:27:4693 CompoundBuffer payload;
[email protected]6357e602010-11-16 01:53:0794 // TODO(sergeyu): This copy would not be necessary CompoundBuffer was used
95 // inside of VideoPacket.
[email protected]c56acf54ff2010-11-19 23:44:4596 payload.AppendCopyOf(packet->data().data(), packet->data().size());
[email protected]b3c03402010-11-16 01:27:4697
[email protected]6357e602010-11-16 01:53:0798 Vp8Descriptor vp8_desriptor;
99 // TODO(sergeyu): Add a flag in VideoPacket that indicates whether this is a
100 // key frame or not.
101 vp8_desriptor.non_reference_frame = false;
102 vp8_desriptor.picture_id = kuint32max;
103
104 int position = 0;
105 while (position < payload.total_bytes()) {
106 int size = std::min(kMtu, payload.total_bytes() - position);
107
108 // Frame beginning flag is set only for the first packet in the first
109 // partition.
110 vp8_desriptor.frame_beginning =
[email protected]c56acf54ff2010-11-19 23:44:45111 (packet->flags() & VideoPacket::FIRST_PACKET) != 0 && position == 0;
[email protected]6357e602010-11-16 01:53:07112
113 // Marker bit is set only for the last packet in the last partition.
114 bool marker = (position + size) == payload.total_bytes() &&
[email protected]c56acf54ff2010-11-19 23:44:45115 (packet->flags() & VideoPacket::LAST_PACKET) != 0;
[email protected]6357e602010-11-16 01:53:07116
117 // Set fragmentation flag appropriately.
118 if (position == 0) {
119 if (size == payload.total_bytes()) {
120 vp8_desriptor.fragmentation_info = Vp8Descriptor::NOT_FRAGMENTED;
121 } else {
122 vp8_desriptor.fragmentation_info = Vp8Descriptor::FIRST_FRAGMENT;
123 }
124 } else {
125 if (position + size == payload.total_bytes()) {
126 vp8_desriptor.fragmentation_info = Vp8Descriptor::LAST_FRAGMENT;
127 } else {
128 vp8_desriptor.fragmentation_info = Vp8Descriptor::MIDDLE_FRAGMENT;
129 }
130 }
131
132 // Create CompoundBuffer for the chunk.
133 CompoundBuffer chunk;
134 chunk.CopyFrom(payload, position, position + size);
135
136 // And send it.
[email protected]c56acf54ff2010-11-19 23:44:45137 rtp_writer_.SendPacket(packet->timestamp(), marker, vp8_desriptor, chunk);
[email protected]6357e602010-11-16 01:53:07138
139 position += size;
140 }
[email protected]6357e602010-11-16 01:53:07141 DCHECK_EQ(position, payload.total_bytes());
[email protected]c56acf54ff2010-11-19 23:44:45142
[email protected]9e2a3132011-10-07 05:07:40143 done.Run();
[email protected]14fd1a602010-11-03 04:17:09144}
145
146int RtpVideoWriter::GetPendingPackets() {
147 return rtp_writer_.GetPendingPackets();
148}
149
[email protected]d87c4042010-11-04 00:46:01150} // namespace protocol
[email protected]14fd1a602010-11-03 04:17:09151} // namespace remoting