Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: remoting/client/rectangle_update_decoder.cc

Issue 4476003: Add VideoPacket struct for video packets. Refactor Decode interface to use it. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed compilation on windows and mac Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/client/rectangle_update_decoder.h" 5 #include "remoting/client/rectangle_update_decoder.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/message_loop.h" 8 #include "base/message_loop.h"
9 #include "media/base/callback.h" 9 #include "media/base/callback.h"
10 #include "remoting/base/decoder.h" 10 #include "remoting/base/decoder.h"
11 #include "remoting/base/decoder_row_based.h" 11 #include "remoting/base/decoder_row_based.h"
12 #include "remoting/base/decoder_vp8.h" 12 #include "remoting/base/decoder_vp8.h"
13 #include "remoting/base/tracer.h" 13 #include "remoting/base/tracer.h"
14 #include "remoting/base/util.h" 14 #include "remoting/base/util.h"
15 #include "remoting/client/frame_consumer.h" 15 #include "remoting/client/frame_consumer.h"
16 #include "remoting/protocol/chromotocol_config.h"
16 17
17 using media::AutoTaskRunner; 18 using media::AutoTaskRunner;
18 19
19 namespace remoting { 20 namespace remoting {
20 21
21 namespace { 22 namespace {
22 23
23 class PartialFrameCleanup : public Task { 24 class PartialFrameCleanup : public Task {
24 public: 25 public:
25 PartialFrameCleanup(media::VideoFrame* frame, UpdatedRects* rects) 26 PartialFrameCleanup(media::VideoFrame* frame, UpdatedRects* rects)
(...skipping 14 matching lines...) Expand all
40 41
41 RectangleUpdateDecoder::RectangleUpdateDecoder(MessageLoop* message_loop, 42 RectangleUpdateDecoder::RectangleUpdateDecoder(MessageLoop* message_loop,
42 FrameConsumer* consumer) 43 FrameConsumer* consumer)
43 : message_loop_(message_loop), 44 : message_loop_(message_loop),
44 consumer_(consumer) { 45 consumer_(consumer) {
45 } 46 }
46 47
47 RectangleUpdateDecoder::~RectangleUpdateDecoder() { 48 RectangleUpdateDecoder::~RectangleUpdateDecoder() {
48 } 49 }
49 50
50 void RectangleUpdateDecoder::DecodePacket(const VideoPacket& packet, 51 void RectangleUpdateDecoder::Initialize(const ChromotocolConfig* config) {
52 screen_size_ = gfx::Size(config->initial_resolution().width,
53 config->initial_resolution().height);
54
55 // Initialize decoder based on the selected codec.
56 ChannelConfig::Codec codec = config->video_config().codec;
57 if (codec == ChannelConfig::CODEC_VERBATIM) {
58 TraceContext::tracer()->PrintString("Creating Verbatim decoder.");
59 decoder_.reset(DecoderRowBased::CreateVerbatimDecoder());
60 } else if (codec == ChannelConfig::CODEC_ZIP) {
61 TraceContext::tracer()->PrintString("Creating Zlib decoder");
62 decoder_.reset(DecoderRowBased::CreateZlibDecoder());
63 // TODO(sergeyu): Enable VP8 on ARM builds.
64 #if !defined(ARCH_CPU_ARM_FAMILY)
65 } else if (codec == ChannelConfig::CODEC_VP8) {
66 TraceContext::tracer()->PrintString("Creating VP8 decoder");
67 decoder_.reset(new DecoderVp8());
68 #endif
69 } else {
70 NOTREACHED() << "Invalid Encoding found: " << codec;
71 }
72 }
73
74 void RectangleUpdateDecoder::DecodePacket(const VideoPacket* packet,
51 Task* done) { 75 Task* done) {
52 if (message_loop_ != MessageLoop::current()) { 76 if (message_loop_ != MessageLoop::current()) {
53 message_loop_->PostTask( 77 message_loop_->PostTask(
54 FROM_HERE, 78 FROM_HERE,
55 NewTracedMethod(this, 79 NewTracedMethod(this,
56 &RectangleUpdateDecoder::DecodePacket, packet, 80 &RectangleUpdateDecoder::DecodePacket, packet,
57 done)); 81 done));
58 return; 82 return;
59 } 83 }
60 AutoTaskRunner done_runner(done); 84 AutoTaskRunner done_runner(done);
61 85
62 TraceContext::tracer()->PrintString("Decode Packet called."); 86 TraceContext::tracer()->PrintString("Decode Packet called.");
63 87
64 if (!IsValidPacket(packet)) { 88 if (!decoder_->IsReadyForData()) {
65 LOG(ERROR) << "Received invalid packet."; 89 InitializeDecoder(
66 return; 90 NewTracedMethod(this,
67 } 91 &RectangleUpdateDecoder::ProcessPacketData,
68 92 packet, done_runner.release()));
69 Task* process_packet_data =
70 NewTracedMethod(this,
71 &RectangleUpdateDecoder::ProcessPacketData,
72 packet, done_runner.release());
73
74 if (packet.flags() | VideoPacket::FIRST_PACKET) {
75 const VideoPacketFormat& format = packet.format();
76
77 InitializeDecoder(format, process_packet_data);
78 } else { 93 } else {
79 process_packet_data->Run(); 94 ProcessPacketData(packet, done_runner.release());
80 delete process_packet_data;
81 } 95 }
82 } 96 }
83 97
84 void RectangleUpdateDecoder::ProcessPacketData( 98 void RectangleUpdateDecoder::ProcessPacketData(
85 const VideoPacket& packet, Task* done) { 99 const VideoPacket* packet, Task* done) {
86 AutoTaskRunner done_runner(done); 100 AutoTaskRunner done_runner(done);
87 101
88 if (!decoder_->IsReadyForData()) { 102 if (!decoder_->IsReadyForData()) {
89 // TODO(ajwong): This whole thing should move into an invalid state. 103 // TODO(ajwong): This whole thing should move into an invalid state.
90 LOG(ERROR) << "Decoder is unable to process data. Dropping packet."; 104 LOG(ERROR) << "Decoder is unable to process data. Dropping packet.";
91 return; 105 return;
92 } 106 }
93 107
94 TraceContext::tracer()->PrintString("Executing Decode."); 108 TraceContext::tracer()->PrintString("Executing Decode.");
95 decoder_->DecodeBytes(packet.data());
96 109
97 if (packet.flags() | VideoPacket::LAST_PACKET) { 110 Decoder::DecodeResult result = decoder_->DecodePacket(packet);
98 decoder_->Reset();
99 111
100 UpdatedRects* rects = new UpdatedRects(); 112 if (result == Decoder::DECODE_DONE) {
101 113 UpdatedRects* rects = decoder_->GetUpdatedRects();
102 // Empty out the list of current updated rects so the decoder can keep
103 // writing new ones while these are processed.
104 rects->swap(updated_rects_);
105
106 consumer_->OnPartialFrameOutput(frame_, rects, 114 consumer_->OnPartialFrameOutput(frame_, rects,
107 new PartialFrameCleanup(frame_, rects)); 115 new PartialFrameCleanup(frame_, rects));
108 } 116 }
109 } 117 }
110 118
111 // static 119 void RectangleUpdateDecoder::InitializeDecoder(Task* done) {
112 bool RectangleUpdateDecoder::IsValidPacket(const VideoPacket& packet) {
113 if (!packet.IsInitialized()) {
114 LOG(WARNING) << "Protobuf consistency checks fail.";
115 return false;
116 }
117
118 // First packet must have a format.
119 if (packet.flags() | VideoPacket::FIRST_PACKET) {
120 if (!packet.has_format()) {
121 LOG(WARNING) << "First packet must have format.";
122 return false;
123 }
124
125 // TODO(ajwong): Verify that we don't need to whitelist encodings.
126 const VideoPacketFormat& format = packet.format();
127 if (!format.has_encoding() ||
128 format.encoding() == VideoPacketFormat::ENCODING_INVALID) {
129 LOG(WARNING) << "Invalid encoding specified.";
130 return false;
131 }
132 }
133
134 // We shouldn't generate null packets.
135 if (!packet.has_data()) {
136 LOG(WARNING) << "Packet w/o data received.";
137 return false;
138 }
139
140 return true;
141 }
142
143 void RectangleUpdateDecoder::InitializeDecoder(const VideoPacketFormat& format,
144 Task* done) {
145 if (message_loop_ != MessageLoop::current()) { 120 if (message_loop_ != MessageLoop::current()) {
146 message_loop_->PostTask( 121 message_loop_->PostTask(
147 FROM_HERE, 122 FROM_HERE,
148 NewTracedMethod(this, 123 NewTracedMethod(this,
149 &RectangleUpdateDecoder::InitializeDecoder, 124 &RectangleUpdateDecoder::InitializeDecoder, done));
150 format, done));
151 return; 125 return;
152 } 126 }
153 AutoTaskRunner done_runner(done); 127 AutoTaskRunner done_runner(done);
154 128
155 // Check if we need to request a new frame. 129 // Check if we need to request a new frame.
156 if (!frame_ || 130 if (!frame_ ||
157 frame_->width() < static_cast<size_t>(format.width()) || 131 frame_->width() != static_cast<size_t>(screen_size_.width()) ||
158 frame_->height() < static_cast<size_t>(format.height())) { 132 frame_->height() != static_cast<size_t>(screen_size_.height())) {
159 if (frame_) { 133 if (frame_) {
160 TraceContext::tracer()->PrintString("Releasing old frame."); 134 TraceContext::tracer()->PrintString("Releasing old frame.");
161 consumer_->ReleaseFrame(frame_); 135 consumer_->ReleaseFrame(frame_);
162 frame_ = NULL; 136 frame_ = NULL;
163 } 137 }
164 TraceContext::tracer()->PrintString("Requesting new frame."); 138 TraceContext::tracer()->PrintString("Requesting new frame.");
165 consumer_->AllocateFrame(media::VideoFrame::RGB32, 139 consumer_->AllocateFrame(media::VideoFrame::RGB32,
166 format.width(), format.height(), 140 screen_size_.width(), screen_size_.height(),
167 base::TimeDelta(), base::TimeDelta(), 141 base::TimeDelta(), base::TimeDelta(),
168 &frame_, 142 &frame_,
169 NewTracedMethod( 143 NewTracedMethod(
170 this, 144 this,
171 &RectangleUpdateDecoder::InitializeDecoder, 145 &RectangleUpdateDecoder::InitializeDecoder,
172 format,
173 done_runner.release())); 146 done_runner.release()));
174 return; 147 return;
175 } 148 }
176 149
177 // TODO(ajwong): We need to handle the allocator failing to create a frame 150 // TODO(ajwong): We need to handle the allocator failing to create a frame
178 // and properly disable this class. 151 // and properly disable this class.
179 CHECK(frame_); 152 CHECK(frame_);
180 153
181 if (decoder_.get()) { 154 decoder_->Reset();
182 // TODO(ajwong): We need to handle changing decoders midstream correctly 155 decoder_->Initialize(frame_);
183 // since someone may feed us a corrupt stream, or manually create a
184 // stream that changes decoders. At the very leask, we should not
185 // crash the process.
186 //
187 // For now though, assume that only one encoding is used throughout.
188 //
189 // Note, this may be as simple as just deleting the current decoder.
190 // However, we need to verify the flushing semantics of the decoder first.
191 CHECK(decoder_->Encoding() == format.encoding());
192 } else {
193 // Initialize a new decoder based on this message encoding.
194 if (format.encoding() == VideoPacketFormat::ENCODING_VERBATIM) {
195 TraceContext::tracer()->PrintString("Creating Verbatim decoder.");
196 decoder_.reset(DecoderRowBased::CreateVerbatimDecoder());
197 } else if (format.encoding() == VideoPacketFormat::ENCODING_ZLIB) {
198 TraceContext::tracer()->PrintString("Creating Zlib decoder");
199 decoder_.reset(DecoderRowBased::CreateZlibDecoder());
200 // TODO(sergeyu): Enable VP8 on ARM builds.
201 #if !defined(ARCH_CPU_ARM_FAMILY)
202 } else if (format.encoding() == VideoPacketFormat::ENCODING_VP8) {
203 TraceContext::tracer()->PrintString("Creating VP8 decoder");
204 decoder_.reset(new DecoderVp8());
205 #endif
206 } else {
207 NOTREACHED() << "Invalid Encoding found: " << format.encoding();
208 }
209 }
210 156
211 // TODO(ajwong): This can happen in the face of corrupt input data. Figure
212 // out the right behavior and make this more resilient.
213 CHECK(updated_rects_.empty());
214
215 gfx::Rect rectangle_size(format.x(), format.y(),
216 format.width(), format.height());
217 updated_rects_.push_back(rectangle_size);
218 decoder_->Initialize(frame_, rectangle_size,
219 GetBytesPerPixel(format.pixel_format()));
220 TraceContext::tracer()->PrintString("Decoder is Initialized"); 157 TraceContext::tracer()->PrintString("Decoder is Initialized");
221 } 158 }
222 159
223 } // namespace remoting 160 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698