blob: ae85f8346da12f428457ebbd61648630d3def57d [file] [log] [blame]
[email protected]14fd1a602010-11-03 04:17:091// Copyright (c) 2010 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 "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)
24 : initialized_(false),
25 rtp_writer_(message_loop) {
[email protected]182ec8f22011-08-11 02:14:3526}
[email protected]14fd1a602010-11-03 04:17:0927
[email protected]86dbc722011-06-30 23:23:3028RtpVideoWriter::~RtpVideoWriter() {
29 Close();
30}
[email protected]14fd1a602010-11-03 04:17:0931
[email protected]182ec8f22011-08-11 02:14:3532void RtpVideoWriter::Init(protocol::Session* session,
33 const InitializedCallback& callback) {
34 initialized_callback_ = callback;
35 session->CreateDatagramChannel(
36 kVideoRtpChannelName,
[email protected]dee7ab52011-08-11 02:51:3437 base::Bind(&RtpVideoWriter::OnChannelReady,
38 base::Unretained(this), true));
[email protected]182ec8f22011-08-11 02:14:3539 session->CreateDatagramChannel(
40 kVideoRtcpChannelName,
[email protected]dee7ab52011-08-11 02:51:3441 base::Bind(&RtpVideoWriter::OnChannelReady,
42 base::Unretained(this), false));
[email protected]182ec8f22011-08-11 02:14:3543}
44
[email protected]dee7ab52011-08-11 02:51:3445void RtpVideoWriter::OnChannelReady(bool rtp, net::Socket* socket) {
[email protected]182ec8f22011-08-11 02:14:3546 if (!socket) {
47 if (!initialized_) {
48 initialized_ = true;
49 initialized_callback_.Run(false);
50 }
51 return;
52 }
53
[email protected]dee7ab52011-08-11 02:51:3454 if (rtp) {
[email protected]182ec8f22011-08-11 02:14:3555 DCHECK(!rtp_channel_.get());
56 rtp_channel_.reset(socket);
57 rtp_writer_.Init(socket);
[email protected]dee7ab52011-08-11 02:51:3458 } else {
[email protected]182ec8f22011-08-11 02:14:3559 DCHECK(!rtcp_channel_.get());
60 rtcp_channel_.reset(socket);
61 // TODO(sergeyu): Use RTCP channel somehow.
62 }
63
64 if (rtp_channel_.get() && rtcp_channel_.get()) {
65 DCHECK(!initialized_);
66 initialized_ = true;
67 initialized_callback_.Run(true);
68 }
[email protected]14fd1a602010-11-03 04:17:0969}
70
[email protected]86dbc722011-06-30 23:23:3071void RtpVideoWriter::Close() {
72 rtp_writer_.Close();
[email protected]182ec8f22011-08-11 02:14:3573 rtp_channel_.reset();
74 rtcp_channel_.reset();
[email protected]86dbc722011-06-30 23:23:3075}
76
[email protected]c56acf54ff2010-11-19 23:44:4577void RtpVideoWriter::ProcessVideoPacket(const VideoPacket* packet, Task* done) {
78 CHECK(packet->format().encoding() == VideoPacketFormat::ENCODING_VP8)
[email protected]6357e602010-11-16 01:53:0779 << "Only VP8 is supported in RTP.";
80
[email protected]b3c03402010-11-16 01:27:4681 CompoundBuffer payload;
[email protected]6357e602010-11-16 01:53:0782 // TODO(sergeyu): This copy would not be necessary CompoundBuffer was used
83 // inside of VideoPacket.
[email protected]c56acf54ff2010-11-19 23:44:4584 payload.AppendCopyOf(packet->data().data(), packet->data().size());
[email protected]b3c03402010-11-16 01:27:4685
[email protected]6357e602010-11-16 01:53:0786 Vp8Descriptor vp8_desriptor;
87 // TODO(sergeyu): Add a flag in VideoPacket that indicates whether this is a
88 // key frame or not.
89 vp8_desriptor.non_reference_frame = false;
90 vp8_desriptor.picture_id = kuint32max;
91
92 int position = 0;
93 while (position < payload.total_bytes()) {
94 int size = std::min(kMtu, payload.total_bytes() - position);
95
96 // Frame beginning flag is set only for the first packet in the first
97 // partition.
98 vp8_desriptor.frame_beginning =
[email protected]c56acf54ff2010-11-19 23:44:4599 (packet->flags() & VideoPacket::FIRST_PACKET) != 0 && position == 0;
[email protected]6357e602010-11-16 01:53:07100
101 // Marker bit is set only for the last packet in the last partition.
102 bool marker = (position + size) == payload.total_bytes() &&
[email protected]c56acf54ff2010-11-19 23:44:45103 (packet->flags() & VideoPacket::LAST_PACKET) != 0;
[email protected]6357e602010-11-16 01:53:07104
105 // Set fragmentation flag appropriately.
106 if (position == 0) {
107 if (size == payload.total_bytes()) {
108 vp8_desriptor.fragmentation_info = Vp8Descriptor::NOT_FRAGMENTED;
109 } else {
110 vp8_desriptor.fragmentation_info = Vp8Descriptor::FIRST_FRAGMENT;
111 }
112 } else {
113 if (position + size == payload.total_bytes()) {
114 vp8_desriptor.fragmentation_info = Vp8Descriptor::LAST_FRAGMENT;
115 } else {
116 vp8_desriptor.fragmentation_info = Vp8Descriptor::MIDDLE_FRAGMENT;
117 }
118 }
119
120 // Create CompoundBuffer for the chunk.
121 CompoundBuffer chunk;
122 chunk.CopyFrom(payload, position, position + size);
123
124 // And send it.
[email protected]c56acf54ff2010-11-19 23:44:45125 rtp_writer_.SendPacket(packet->timestamp(), marker, vp8_desriptor, chunk);
[email protected]6357e602010-11-16 01:53:07126
127 position += size;
128 }
[email protected]6357e602010-11-16 01:53:07129 DCHECK_EQ(position, payload.total_bytes());
[email protected]c56acf54ff2010-11-19 23:44:45130
131 done->Run();
132 delete done;
[email protected]14fd1a602010-11-03 04:17:09133}
134
135int RtpVideoWriter::GetPendingPackets() {
136 return rtp_writer_.GetPendingPackets();
137}
138
[email protected]d87c4042010-11-04 00:46:01139} // namespace protocol
[email protected]14fd1a602010-11-03 04:17:09140} // namespace remoting