Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 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 "ppapi/examples/video_decoder/video_decoder_session.h" | |
| 6 | |
| 7 #include <cstring> | |
| 8 #include <fstream> | |
| 9 #include <iostream> | |
| 10 | |
| 11 #include "ppapi/c/dev/pp_graphics_3d_dev.h" | |
| 12 #include "ppapi/c/dev/ppb_buffer_dev.h" | |
| 13 #include "ppapi/c/pp_errors.h" | |
| 14 #include "ppapi/cpp/dev/context_3d_dev.h" | |
| 15 #include "ppapi/cpp/dev/surface_3d_dev.h" | |
| 16 #include "ppapi/cpp/dev/video_decoder_dev.h" | |
| 17 #include "ppapi/lib/gl/include/GLES2/gl2.h" | |
| 18 | |
| 19 // Pull-based video source to read video data from a file. | |
| 20 class TestVideoSource { | |
| 21 public: | |
| 22 TestVideoSource() | |
| 23 : file_length_(0), | |
| 24 offset_(0) {} | |
| 25 | |
| 26 ~TestVideoSource() {} | |
| 27 | |
| 28 bool Open(const std::string& url) { | |
| 29 // TODO(vmr): Use file_util::ReadFileToString or equivalent to read the file | |
| 30 // if one-shot reading is used. | |
| 31 std::ifstream* file = | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
scoped_ptr, then delete the deletes below :)
Ville-Mikko Rautio
2011/06/03 13:24:39
I am in impression that relying on anything from C
| |
| 32 new std::ifstream(url.c_str(), | |
| 33 std::ios::in | std::ios::binary | std::ios::ate); | |
| 34 if (!file->good()) { | |
| 35 delete file; | |
| 36 return false; | |
| 37 } | |
| 38 file->seekg(0, std::ios::end); | |
| 39 uint32_t length = file->tellg(); | |
| 40 file->seekg(0, std::ios::beg); | |
| 41 mem_ = new uint8_t[length]; | |
| 42 file->read(reinterpret_cast<char*>(mem_), length); | |
| 43 file_length_ = length; | |
| 44 file->close(); | |
| 45 delete file; | |
| 46 return true; | |
| 47 } | |
| 48 | |
| 49 // Reads next packet from the input stream. | |
| 50 // Returns number of read bytes on success, 0 on when there was no valid data | |
| 51 // to be read and -1 if user gave NULL or too small buffer. | |
| 52 // TODO(vmr): Modify to differentiate between errors and EOF. | |
| 53 int32_t Read(uint8_t* target_mem, uint32_t size) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
It looks like you are doing some decoding to split
Ville-Mikko Rautio
2011/06/03 13:24:39
There is possibility to pass the whole bitstream f
| |
| 54 if (!target_mem) | |
| 55 return -1; | |
| 56 uint8_t* unit_begin = NULL; | |
| 57 uint8_t* unit_end = NULL; | |
| 58 uint8_t* ptr = mem_ + offset_; | |
| 59 while (offset_ + 4 < file_length_) { | |
| 60 if (ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 1) { | |
| 61 // start code found | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Complete sentence + explanation of start code.
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 62 if (!unit_begin) { | |
| 63 unit_begin = ptr; | |
| 64 } else { | |
| 65 // back-up 1 byte. | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Complete sentence.
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 66 unit_end = ptr; | |
| 67 break; | |
| 68 } | |
| 69 } | |
| 70 ptr++; | |
| 71 offset_++; | |
| 72 } | |
| 73 if (unit_begin && offset_ + 4 == file_length_) { | |
| 74 // Last unit. Set the unit_end to point to the last byte. | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
The last buffer begins _and_ ends with 0001?
In ot
Ville-Mikko Rautio
2011/06/03 13:24:39
There's no 0001 at the end. +4 needed because of t
| |
| 75 unit_end = ptr + 4; | |
| 76 offset_ += 4; | |
| 77 } else if (!unit_begin || !unit_end) { | |
| 78 // No unit start codes found in buffer. | |
| 79 return 0; | |
| 80 } | |
| 81 if (static_cast<int32_t>(size) >= unit_end - unit_begin) { | |
| 82 memcpy(target_mem, unit_begin, unit_end - unit_begin); | |
| 83 return unit_end - unit_begin; | |
| 84 } | |
| 85 // Rewind to the beginning start code if there is one as it should be | |
| 86 // returned with next Read(). | |
| 87 offset_ = unit_begin - mem_; | |
| 88 return -1; | |
| 89 } | |
| 90 | |
| 91 private: | |
| 92 uint32_t file_length_; | |
| 93 uint32_t offset_; | |
| 94 uint8_t* mem_; | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
scoped_array? At the very least you need to delete
Ville-Mikko Rautio
2011/06/03 13:24:39
True. Added delete for destructor since I am not s
| |
| 95 }; | |
| 96 | |
| 97 LocalVideoBitstreamSource::LocalVideoBitstreamSource(std::string filename) | |
| 98 : file_(filename), | |
| 99 video_source_(new TestVideoSource()), | |
| 100 video_source_open_(false) { | |
| 101 } | |
| 102 | |
| 103 LocalVideoBitstreamSource::~LocalVideoBitstreamSource() { | |
| 104 delete video_source_; | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
No longer needed w/ scoped_ptr
Ville-Mikko Rautio
2011/06/03 13:24:39
Ditto.
| |
| 105 } | |
| 106 | |
| 107 bool LocalVideoBitstreamSource::GetBitstreamUnit( | |
| 108 void* target_mem, | |
| 109 uint32_t target_mem_size_in_bytes, | |
| 110 int32_t* unit_size_in_bytes) { | |
| 111 if (!video_source_open_) { | |
| 112 if (!video_source_->Open(file_)) { | |
| 113 return false; | |
| 114 } | |
| 115 video_source_open_ = true; | |
| 116 } | |
| 117 int32_t read_bytes = video_source_->Read(static_cast<uint8_t*>(target_mem), | |
| 118 target_mem_size_in_bytes); | |
| 119 if (read_bytes <= 0) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: no {} for one-line condition
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 120 return false; | |
| 121 } | |
| 122 *unit_size_in_bytes = read_bytes; | |
| 123 return true; | |
| 124 } | |
| 125 | |
| 126 VideoDecoderSessionClient::~VideoDecoderSessionClient() { | |
| 127 } | |
| 128 | |
| 129 // Constants used by VideoDecoderSession. | |
| 130 static const int32_t kBitstreamBufferCount = 3; | |
| 131 static const int32_t kBitstreamBufferSize = 256 * 1024 * 1024; | |
| 132 static const int32_t kDefaultWidth = 640; | |
| 133 static const int32_t kDefaultHeight = 480; | |
| 134 | |
| 135 bool VideoDecoderSession::Initialize( | |
| 136 const std::vector<uint32_t>& decoder_config, | |
| 137 pp::CompletionCallback completion_callback) { | |
| 138 assert(video_source_ && display_); | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Do this check in the constructor.
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 139 // Default implementation just assumes everything is set up. | |
| 140 if (!AllocateInputBuffers()) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: No {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 141 return false; | |
| 142 } | |
| 143 pp::CompletionCallback cb = cb_factory_.NewCallback( | |
| 144 &VideoDecoderSession::OnInitializeDone, completion_callback); | |
| 145 video_decoder_ = new pp::VideoDecoder(instance_, decoder_config, cb, this); | |
| 146 if (!video_decoder_) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: No {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 147 return false; | |
| 148 } | |
| 149 return true; | |
| 150 } | |
| 151 | |
| 152 bool VideoDecoderSession::Run(pp::CompletionCallback completion_callback) { | |
| 153 assert(state_ == kInitialized); | |
| 154 // Start the streaming by dispatching the first buffers one by one. | |
| 155 for (std::map<int32_t, PP_VideoBitstreamBuffer_Dev>::iterator it = | |
| 156 bitstream_buffers_.begin(); | |
| 157 it == bitstream_buffers_.end(); | |
| 158 it++) { | |
| 159 if (!ReadAndDispatchBitstreamUnit((*it).first)) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 160 return false; | |
| 161 } | |
| 162 } | |
| 163 // Once streaming has been started, we're running. | |
| 164 ChangeState(kRunning); | |
| 165 completion_callback.Run(PP_OK); | |
| 166 return true; | |
| 167 } | |
| 168 | |
| 169 bool VideoDecoderSession::Stop(pp::CompletionCallback completion_callback) { | |
| 170 assert(state_ == kRunning); | |
| 171 // Stop the playback. | |
| 172 ChangeState(kInitialized); | |
| 173 return true; | |
| 174 } | |
| 175 | |
| 176 bool VideoDecoderSession::Flush(pp::CompletionCallback completion_callback) { | |
| 177 assert(state_ == kRunning); | |
| 178 // Issue the flush request. | |
| 179 ChangeState(kFlushing); | |
| 180 video_decoder_->Flush(cb_factory_.NewCallback( | |
| 181 &VideoDecoderSession::OnUserFlushDone, state_, completion_callback)); | |
| 182 return true; | |
| 183 } | |
| 184 | |
| 185 bool VideoDecoderSession::Teardown(pp::CompletionCallback completion_callback) { | |
| 186 assert(state_ == kInitialized); | |
| 187 // Teardown the resources. | |
| 188 FreeInputBuffers(); | |
| 189 ChangeState(kCreated); | |
| 190 completion_callback.Run(PP_OK); | |
| 191 return true; | |
| 192 } | |
| 193 | |
| 194 void VideoDecoderSession::ProvidePictureBuffers( | |
| 195 uint32_t requested_num_of_buffers, | |
| 196 const std::vector<uint32_t>& buffer_properties) { | |
|
vjain
2011/05/31 22:29:07
What is the purpose of buffer_properties?
Will GPU
Ville-Mikko Rautio
2011/06/01 11:50:08
Buffer properties will contain width & height and
vrk (LEFT CHROMIUM)
2011/06/01 22:41:31
Actually, this C++ API is not up to date with the
Ville-Mikko Rautio
2011/06/03 13:24:39
C++ API change (http://codereview.chromium.org/708
| |
| 197 // Currently we support only GLES buffer allocation. | |
| 198 std::vector<PP_GLESBuffer_Dev> buffers; | |
| 199 for (uint32_t i = 0; i < requested_num_of_buffers; i++) { | |
| 200 PP_GLESBuffer_Dev gles_buffer; | |
| 201 if (!display_->ProvideGLESPictureBuffer(buffer_properties, &gles_buffer)) { | |
| 202 video_decoder_->Abort(cb_factory_.NewCallback( | |
| 203 &VideoDecoderSession::OnAbortDone)); | |
| 204 return; | |
| 205 } | |
| 206 buffers.push_back(gles_buffer); | |
| 207 } | |
| 208 video_decoder_->AssignGLESBuffers(buffers.size(), buffers); | |
| 209 } | |
| 210 | |
| 211 void VideoDecoderSession::DismissPictureBuffer(int32_t picture_buffer_id) { | |
| 212 if (!display_->DismissPictureBuffer(picture_buffer_id)) { | |
| 213 assert(!"Failed to dismiss picture buffer properly"); | |
| 214 return; | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 void VideoDecoderSession::PictureReady(const PP_Picture_Dev& picture) { | |
| 219 display_->DrawPicture(picture, cb_factory_.NewCallback( | |
| 220 &VideoDecoderSession::OnDrawPictureDone, picture.picture_buffer_id)); | |
| 221 } | |
| 222 | |
| 223 void VideoDecoderSession::NotifyEndOfStream() { | |
| 224 end_of_stream_ = true; | |
| 225 video_decoder_->Flush(cb_factory_.NewCallback( | |
| 226 &VideoDecoderSession::OnInternalFlushDone)); | |
| 227 } | |
| 228 | |
| 229 void VideoDecoderSession::NotifyError(PP_VideoDecodeError_Dev error) { | |
| 230 video_decoder_->Flush(cb_factory_.NewCallback( | |
| 231 &VideoDecoderSession::OnInternalFlushDone)); | |
| 232 } | |
| 233 | |
| 234 int32_t VideoDecoderSession::GetUniqueId() { | |
| 235 // Not exactly unique in the current form but close enough for use case. | |
| 236 return next_id_++; | |
| 237 } | |
| 238 | |
| 239 void VideoDecoderSession::OnInitializeDone(int32_t result, | |
| 240 pp::CompletionCallback callback) { | |
| 241 if (state_ != kCreated) { | |
| 242 ChangeState(kCreated); | |
| 243 callback.Run(PP_ERROR_ABORTED); | |
| 244 } | |
| 245 if (result != PP_OK) { | |
| 246 ChangeState(kInitialized); | |
| 247 callback.Run(result); | |
| 248 } | |
| 249 callback.Run(PP_OK); | |
| 250 } | |
| 251 | |
| 252 void VideoDecoderSession::OnBitstreamBufferProcessed( | |
|
vjain
2011/06/02 01:04:52
Hi Ville-Mikko,
When the GPU decoder returns the b
Ville-Mikko Rautio
2011/06/03 13:24:39
I am not sure what are you referring to. Bitstream
| |
| 253 int32_t result, | |
| 254 int32_t bitstream_buffer_id) { | |
| 255 // Reuse each bitstream buffer that has been processed by reading data into it | |
| 256 // as long as there is more and pass that for decoding. | |
| 257 ReadAndDispatchBitstreamUnit(bitstream_buffer_id); | |
| 258 } | |
| 259 | |
| 260 void VideoDecoderSession::OnDrawPictureDone(int32_t result, | |
| 261 int32_t picture_buffer_id) { | |
| 262 video_decoder_->ReusePictureBuffer(picture_buffer_id); | |
| 263 } | |
| 264 | |
| 265 void VideoDecoderSession::OnUserFlushDone(int32_t result, | |
| 266 State target_state, | |
| 267 pp::CompletionCallback callback) { | |
| 268 assert(state_ == kFlushing); | |
| 269 // It was a Flush request, return to the state where we started. | |
| 270 ChangeState(target_state); | |
| 271 callback.Run(result); | |
| 272 } | |
| 273 | |
| 274 void VideoDecoderSession::OnInternalFlushDone(int32_t result) { | |
| 275 if (end_of_stream_) { | |
| 276 // It was end of stream flush. | |
| 277 video_decoder_->Abort(cb_factory_.NewCallback( | |
| 278 &VideoDecoderSession::OnAbortDone)); | |
| 279 } else { | |
| 280 assert(!"Unhandled flush completion!"); | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 void VideoDecoderSession::OnAbortDone(int32_t result) { | |
| 285 client_->OnSessionCompleted(result); | |
| 286 } | |
| 287 | |
| 288 bool VideoDecoderSession::AllocateInputBuffers() { | |
| 289 buffer_if_ = static_cast<const struct PPB_Buffer_Dev*>( | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
?? Why is this field being set here? Shouldn't thi
Ville-Mikko Rautio
2011/06/03 13:24:39
Moved to ctor and added assert for variable.
| |
| 290 pp::Module::Get()->GetBrowserInterface(PPB_BUFFER_DEV_INTERFACE)); | |
| 291 if (!buffer_if_) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Removed
| |
| 292 return false; | |
| 293 } | |
| 294 // Allocate |kBitstreamBufferCount| bitstream buffers of | |
| 295 // |kBitstreamBufferSize| bytes. | |
| 296 for (int32_t i = 0; i < kBitstreamBufferCount; i++) { | |
| 297 PP_VideoBitstreamBuffer_Dev bitstream_buffer; | |
| 298 bitstream_buffer.data = buffer_if_->Create(instance_->pp_instance(), | |
| 299 kBitstreamBufferSize); | |
| 300 if (bitstream_buffer.data == 0) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 301 return false; | |
| 302 } | |
| 303 bitstream_buffer.size = 0; | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
This should be kBitstreamBufferSize with change me
Ville-Mikko Rautio
2011/06/03 13:24:39
This is the amount of valid data in buffer, so I d
| |
| 304 bitstream_buffer.id = GetUniqueId(); | |
| 305 bitstream_buffers_[bitstream_buffer.id] = bitstream_buffer; | |
| 306 } | |
| 307 return true; | |
| 308 } | |
| 309 | |
| 310 void VideoDecoderSession::FreeInputBuffers() { | |
| 311 std::map<int32_t, PP_VideoBitstreamBuffer_Dev>::iterator it; | |
| 312 for (it = bitstream_buffers_.begin(); it != bitstream_buffers_.end(); it++) { | |
| 313 std::pair<int32_t, PP_VideoBitstreamBuffer_Dev> pair = *it; | |
| 314 PP_VideoBitstreamBuffer_Dev bitstream_buffer = pair.second; | |
| 315 pp::Module::Get()->core()->ReleaseResource(bitstream_buffer.data); | |
| 316 bitstream_buffers_.erase(it); | |
| 317 } | |
| 318 } | |
| 319 | |
| 320 bool VideoDecoderSession::ReadAndDispatchBitstreamUnit( | |
| 321 int32_t bitstream_buffer_id) { | |
| 322 // Get the target memory and read the bitstream unit into it. | |
| 323 if (bitstream_buffers_.find(bitstream_buffer_id) == | |
| 324 bitstream_buffers_.end()) { | |
| 325 return false; | |
| 326 } | |
| 327 PP_VideoBitstreamBuffer_Dev bitstream_buffer = | |
| 328 bitstream_buffers_[bitstream_buffer_id]; | |
| 329 void* target_mem = buffer_if_->Map(bitstream_buffer.data); | |
| 330 if (target_mem == NULL) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 331 return false; | |
| 332 } | |
| 333 uint32_t size_in_bytes = 0; | |
| 334 if (!buffer_if_->Describe(bitstream_buffer.data, &size_in_bytes)) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 335 return false; | |
| 336 } | |
| 337 bool success = video_source_->GetBitstreamUnit(target_mem, size_in_bytes, | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
It's wasteful to allocate a buffer of kBitstreamBu
Ville-Mikko Rautio
2011/06/03 13:24:39
Already commented above. You cannot arbitrarily sp
| |
| 338 &bitstream_buffer.size); | |
| 339 if (!success) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 340 return false; | |
| 341 } | |
| 342 // Dispatch the bitstream unit to the decoder. | |
| 343 success = video_decoder_->Decode( | |
| 344 bitstream_buffers_[bitstream_buffer_id], | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
bitstream_buffer?
Ville-Mikko Rautio
2011/06/03 13:24:39
Yep. Also, I changed the bitstream_buffer into ref
| |
| 345 cb_factory_.NewCallback( | |
| 346 &VideoDecoderSession::OnBitstreamBufferProcessed, | |
| 347 bitstream_buffer_id)); | |
| 348 // Finally unmap the buffer for this round. | |
| 349 buffer_if_->Unmap(bitstream_buffer.data); | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Unmap deletes the bitstream data. Shouldn't we onl
Ville-Mikko Rautio
2011/06/03 13:24:39
True. Done.
| |
| 350 return success; | |
| 351 } | |
| 352 | |
| 353 void VideoDecoderSession::ChangeState(State to_state) { | |
| 354 state_ = to_state; | |
| 355 } | |
| 356 | |
| 357 int32_t VideoDecoderSession::next_id_ = 1; | |
| 358 | |
| 359 // Pass-through vertex shader. | |
| 360 static const char kVertexShader[] = | |
| 361 "precision highp float; precision highp int;\n" | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
I don't believe these precision specifiers are nec
Ville-Mikko Rautio
2011/06/03 13:24:39
I am by no means shader expert, so I'll just take
| |
| 362 "varying vec2 interp_tc;\n" | |
| 363 "\n" | |
| 364 "attribute vec4 in_pos;\n" | |
| 365 "attribute vec2 in_tc;\n" | |
| 366 "\n" | |
| 367 "void main() {\n" | |
| 368 " interp_tc = in_tc;\n" | |
| 369 " gl_Position = in_pos;\n" | |
| 370 "}\n"; | |
| 371 | |
| 372 // Color shader for EGLImage. | |
| 373 static const char kFragmentShaderEgl[] = | |
| 374 "precision mediump float;\n" | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Ditto above.
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 375 "precision mediump int;\n" | |
| 376 "varying vec2 interp_tc;\n" | |
| 377 "\n" | |
| 378 "uniform sampler2D tex;\n" | |
| 379 "\n" | |
| 380 "void main() {\n" | |
| 381 " gl_FragColor = texture2D(tex, interp_tc);\n" | |
| 382 "}\n"; | |
| 383 | |
| 384 // Buffer size for compile errors. | |
| 385 static const unsigned int kShaderErrorSize = 4096; | |
| 386 | |
| 387 void GLES2Display::Graphics3DContextLost() { | |
| 388 assert(!"GLES2: Unexpectedly lost graphics context"); | |
| 389 } | |
| 390 | |
| 391 bool GLES2Display::Initialize() { | |
| 392 if (!InitGL(surface_size_.width, surface_size_.height)) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 393 return false; | |
| 394 } | |
| 395 ProgramShaders(); | |
| 396 return true; | |
| 397 } | |
| 398 | |
| 399 bool GLES2Display::ProvideGLESPictureBuffer( | |
| 400 const std::vector<uint32_t>& buffer_properties, | |
| 401 PP_GLESBuffer_Dev* picture_buffer) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Would make sense to also do the initial call to Te
Ville-Mikko Rautio
2011/06/03 13:24:39
I don't know GL well, so I will need your help in
| |
| 402 GLuint texture; | |
| 403 // Generate texture and bind (effectively allocate) it. | |
| 404 gles2_if_->GenTextures(context_->pp_resource(), 1, &texture); | |
| 405 gles2_if_->BindTexture(context_->pp_resource(), GL_TEXTURE_2D, texture); | |
| 406 picture_buffer->context = 0; // TODO(vmr): Get proper context id. | |
| 407 picture_buffer->texture_id = texture; | |
| 408 picture_buffer->info.id = VideoDecoderSession::GetUniqueId(); | |
| 409 picture_buffer->info.size.width = surface_size_.width; | |
| 410 picture_buffer->info.size.height = surface_size_.height; | |
| 411 // Store the values into the map for GLES buffers. | |
| 412 gles_buffers_[picture_buffer->info.id] = *picture_buffer; | |
| 413 assertNoGLError(); | |
| 414 return true; | |
| 415 } | |
| 416 | |
| 417 bool GLES2Display::DismissPictureBuffer(int32_t picture_buffer_id) { | |
| 418 gles2_if_->DeleteTextures(context_->pp_resource(), 1, | |
| 419 &gles_buffers_[picture_buffer_id].texture_id); | |
| 420 gles_buffers_.erase(picture_buffer_id); | |
| 421 return true; | |
| 422 } | |
| 423 | |
| 424 bool GLES2Display::DrawPicture(const PP_Picture_Dev& picture, | |
| 425 pp::CompletionCallback completion_callback) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
nit: add space before pp
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 426 // Decoder has finished decoding picture into the texture, we'll have to just | |
| 427 // draw the texture to the color buffer and swap the surfaces. | |
| 428 // Clear the color buffer. | |
| 429 gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT | | |
| 430 GL_DEPTH_BUFFER_BIT); | |
| 431 // Load the texture into texture unit 0. | |
| 432 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0); | |
| 433 gles2_if_->BindTexture(context_->pp_resource(), GL_TEXTURE_2D, | |
| 434 gles_buffers_[picture.picture_buffer_id].texture_id); | |
| 435 // Draw the texture. | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
You never copy data into the texture (TexImage2D/M
Ville-Mikko Rautio
2011/06/03 13:24:39
See above comment about ProvideGLESPictureBuffer.
| |
| 436 gles2_if_->DrawArrays(context_->pp_resource(), GL_TRIANGLE_STRIP, 0, 4); | |
| 437 // Force the execution of pending commands. | |
| 438 // TODO(vmr): Do we have to do this? Can we rely command buffer to execute the | |
| 439 // commands without Finish call? | |
| 440 gles2_if_->Finish(context_->pp_resource()); | |
| 441 assertNoGLError(); | |
| 442 | |
| 443 int32_t error = surface_->SwapBuffers(completion_callback); | |
| 444 if (error != PP_OK) { | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
| 445 return false; | |
| 446 } | |
| 447 assertNoGLError(); | |
| 448 return true; | |
| 449 } | |
| 450 | |
| 451 void GLES2Display::assertNoGLError() { | |
| 452 assert(!gles2_if_->GetError(context_->pp_resource())); | |
| 453 } | |
| 454 | |
| 455 bool GLES2Display::InitGL(int width, int height) { | |
| 456 assert(width && height); | |
| 457 gles2_if_ = static_cast<const struct PPB_OpenGLES2_Dev*>( | |
| 458 pp::Module::Get()->GetBrowserInterface(PPB_OPENGLES2_DEV_INTERFACE)); | |
| 459 // Firstly, we need OpenGL ES context associated with the display our plugin | |
| 460 // is rendering to. | |
| 461 if (context_) delete(context_); | |
| 462 context_ = new pp::Context3D_Dev(*instance_, 0, pp::Context3D_Dev(), NULL); | |
| 463 assert(!context_->is_null()); | |
| 464 // Then we need surface bound to our fresh context. We'll be actually drawing | |
| 465 // on this surface and swapping that surface to refresh the displayable data | |
| 466 // of the plugin. | |
| 467 int32_t surface_attributes[] = { | |
| 468 PP_GRAPHICS3DATTRIB_WIDTH, surface_size_.width, | |
| 469 PP_GRAPHICS3DATTRIB_HEIGHT, surface_size_.height, | |
| 470 PP_GRAPHICS3DATTRIB_NONE | |
| 471 }; | |
| 472 if (surface_) delete(surface_); | |
| 473 surface_ = new pp::Surface3D_Dev(*instance_, 0, surface_attributes); | |
| 474 assert(!surface_->is_null()); | |
| 475 int32_t bind_error = context_->BindSurfaces(*surface_, *surface_); | |
| 476 if (!bind_error) { | |
| 477 assert(bind_error); | |
| 478 } | |
| 479 assertNoGLError(); | |
| 480 | |
| 481 bool success = instance_->BindGraphics(*surface_); | |
| 482 if (!success) { | |
| 483 assert(success); | |
| 484 } | |
| 485 // Clear the color buffer with opaque white for starters. | |
| 486 gles2_if_->ClearColor(context_->pp_resource(), 1.0, 1.0, 1.0, 0.0); | |
| 487 gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT); | |
| 488 // Set the viewport to match the whole GL window. | |
| 489 gles2_if_->Viewport(context_->pp_resource(), 0, 0, surface_size_.width, | |
| 490 surface_size_.height); | |
| 491 assertNoGLError(); | |
| 492 return true; | |
| 493 } | |
| 494 | |
| 495 void GLES2Display::CreateShader(GLuint program, GLenum type, | |
| 496 const char* source, | |
| 497 int size) { | |
| 498 GLuint shader = gles2_if_->CreateShader(context_->pp_resource(), type); | |
| 499 gles2_if_->ShaderSource( | |
| 500 context_->pp_resource(), shader, 1, &source, &size); | |
| 501 gles2_if_->CompileShader(context_->pp_resource(), shader); | |
| 502 | |
| 503 int result = GL_FALSE; | |
| 504 gles2_if_->GetShaderiv( | |
| 505 context_->pp_resource(), shader, GL_COMPILE_STATUS, &result); | |
| 506 if (!result) { | |
| 507 char log[kShaderErrorSize]; | |
| 508 int len = 0; | |
| 509 gles2_if_->GetShaderInfoLog(context_->pp_resource(), shader, | |
| 510 kShaderErrorSize - 1, &len, log); | |
| 511 log[len] = 0; | |
| 512 assert(result); | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
You never use log... change to fail with "log" as
Ville-Mikko Rautio
2011/06/03 13:24:39
In Pepper code?
| |
| 513 } | |
| 514 gles2_if_->AttachShader(context_->pp_resource(), program, shader); | |
| 515 gles2_if_->DeleteShader(context_->pp_resource(), shader); | |
| 516 } | |
| 517 | |
| 518 void GLES2Display::LinkProgram(const PPB_OpenGLES2_Dev* gles2_if_ ) { | |
| 519 gles2_if_->LinkProgram(context_->pp_resource(), program_); | |
| 520 int result = GL_FALSE; | |
| 521 gles2_if_->GetProgramiv(context_->pp_resource(), program_, GL_LINK_STATUS, | |
| 522 &result); | |
| 523 if (!result) { | |
| 524 char log[kShaderErrorSize]; | |
| 525 int len = 0; | |
| 526 gles2_if_->GetProgramInfoLog(context_->pp_resource(), program_, | |
| 527 kShaderErrorSize - 1, &len, log); | |
| 528 log[len] = 0; | |
| 529 assert(result); | |
| 530 } | |
| 531 gles2_if_->UseProgram(context_->pp_resource(), program_); | |
| 532 } | |
| 533 | |
| 534 void GLES2Display::ProgramShaders() { | |
| 535 // Vertices for a full screen quad. | |
| 536 static const float kVertices[] = { | |
| 537 -1.f, 1.f, | |
| 538 -1.f, -1.f, | |
| 539 1.f, 1.f, | |
| 540 1.f, -1.f, | |
| 541 }; | |
| 542 | |
| 543 // Texture Coordinates mapping the entire texture for EGL image. | |
| 544 static const float kTextureCoordsEgl[] = { | |
| 545 0, 1, | |
| 546 0, 0, | |
| 547 1, 1, | |
| 548 1, 0, | |
| 549 }; | |
| 550 program_ = gles2_if_->CreateProgram(context_->pp_resource()); | |
| 551 | |
| 552 // Create shader for EGL image | |
| 553 CreateShader(program_, GL_VERTEX_SHADER, | |
| 554 kVertexShader, sizeof(kVertexShader)); | |
| 555 CreateShader(program_, GL_FRAGMENT_SHADER, | |
| 556 kFragmentShaderEgl, sizeof(kFragmentShaderEgl)); | |
| 557 LinkProgram(gles2_if_); | |
| 558 | |
| 559 assertNoGLError(); | |
| 560 // Bind parameters. | |
| 561 gles2_if_->Uniform1i(context_->pp_resource(), gles2_if_-> | |
| 562 GetUniformLocation(context_->pp_resource(), program_, | |
| 563 "tex"), 0); | |
| 564 gles2_if_->GenBuffers(context_->pp_resource(), 1, &vertex_buffer_); | |
| 565 gles2_if_->BindBuffer(context_->pp_resource(), GL_ARRAY_BUFFER, | |
| 566 vertex_buffer_); | |
| 567 gles2_if_->BufferData(context_->pp_resource(), GL_ARRAY_BUFFER, | |
| 568 8 * sizeof(kVertices[0]), kVertices, GL_STREAM_DRAW); | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Should this be GL_STATIC_DRAW?
Ville-Mikko Rautio
2011/06/03 13:24:39
I think both will work. I took your suggestion. Do
| |
| 569 | |
| 570 assertNoGLError(); | |
| 571 int pos_location = gles2_if_->GetAttribLocation(context_->pp_resource(), | |
| 572 program_, "in_pos"); | |
| 573 gles2_if_->EnableVertexAttribArray(context_->pp_resource(), pos_location); | |
| 574 gles2_if_->VertexAttribPointer(context_->pp_resource(), pos_location, 2, | |
| 575 GL_FLOAT, GL_FALSE, 0, 0); | |
| 576 | |
| 577 assertNoGLError(); | |
| 578 gles2_if_->GenBuffers(context_->pp_resource(), 1, &fragment_buffer_); | |
| 579 gles2_if_->BindBuffer(context_->pp_resource(), GL_ARRAY_BUFFER, | |
| 580 fragment_buffer_); | |
| 581 gles2_if_->BufferData(context_->pp_resource(), GL_ARRAY_BUFFER, | |
| 582 8 * sizeof(kTextureCoordsEgl[0]), | |
| 583 kTextureCoordsEgl, GL_STREAM_DRAW); | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Ditto above.
Ville-Mikko Rautio
2011/06/03 13:24:39
Ditto.
| |
| 584 assertNoGLError(); | |
| 585 int tc_location = gles2_if_->GetAttribLocation(context_->pp_resource(), | |
| 586 program_, "in_tc"); | |
| 587 gles2_if_->EnableVertexAttribArray(context_->pp_resource(), tc_location); | |
| 588 gles2_if_->VertexAttribPointer(context_->pp_resource(), tc_location, 2, | |
| 589 GL_FLOAT, GL_FALSE, 0, kTextureCoordsEgl); | |
| 590 gles2_if_->VertexAttribPointer(context_->pp_resource(), tc_location, 2, | |
| 591 GL_FLOAT, GL_FALSE, 0, 0); | |
| 592 gles2_if_->Enable(context_->pp_resource(), GL_DEPTH_TEST); | |
|
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
What is GL_DEPTH_TEST?
Ville-Mikko Rautio
2011/06/03 13:24:39
I believe it is feature of the fragment pipeline i
| |
| 593 assertNoGLError(); | |
| 594 } | |
| 595 | |
| OLD | NEW |