| OLD | NEW |
| 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2014 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 <stdio.h> | 5 #include <stdio.h> |
| 6 #include <string.h> | 6 #include <string.h> |
| 7 | 7 |
| 8 #include <iostream> | 8 #include <iostream> |
| 9 #include <queue> | 9 #include <queue> |
| 10 #include <sstream> | 10 #include <sstream> |
| 11 | 11 |
| 12 #include "ppapi/c/pp_errors.h" | 12 #include "ppapi/c/pp_errors.h" |
| 13 #include "ppapi/c/ppb_console.h" | 13 #include "ppapi/c/ppb_console.h" |
| 14 #include "ppapi/c/ppb_opengles2.h" | 14 #include "ppapi/c/ppb_opengles2.h" |
| 15 #include "ppapi/cpp/graphics_3d.h" | 15 #include "ppapi/cpp/graphics_3d.h" |
| 16 #include "ppapi/cpp/graphics_3d_client.h" | 16 #include "ppapi/cpp/graphics_3d_client.h" |
| 17 #include "ppapi/cpp/input_event.h" | 17 #include "ppapi/cpp/input_event.h" |
| 18 #include "ppapi/cpp/instance.h" | 18 #include "ppapi/cpp/instance.h" |
| 19 #include "ppapi/cpp/module.h" | 19 #include "ppapi/cpp/module.h" |
| 20 #include "ppapi/cpp/rect.h" | 20 #include "ppapi/cpp/rect.h" |
| 21 #include "ppapi/cpp/var.h" | 21 #include "ppapi/cpp/var.h" |
| 22 #include "ppapi/cpp/video_decoder.h" | 22 #include "ppapi/cpp/video_decoder.h" |
| 23 |
| 24 // One of these should be defined. |
| 25 //#define TEST_H264 |
| 26 #define TEST_VP8 |
| 23 #include "ppapi/examples/video_decode/testdata.h" | 27 #include "ppapi/examples/video_decode/testdata.h" |
| 28 |
| 24 #include "ppapi/lib/gl/include/GLES2/gl2.h" | 29 #include "ppapi/lib/gl/include/GLES2/gl2.h" |
| 25 #include "ppapi/lib/gl/include/GLES2/gl2ext.h" | 30 #include "ppapi/lib/gl/include/GLES2/gl2ext.h" |
| 26 #include "ppapi/utility/completion_callback_factory.h" | 31 #include "ppapi/utility/completion_callback_factory.h" |
| 27 | 32 |
| 28 // Use assert as a poor-man's CHECK, even in non-debug mode. | 33 // Use assert as a poor-man's CHECK, even in non-debug mode. |
| 29 // Since <assert.h> redefines assert on every inclusion (it doesn't use | 34 // Since <assert.h> redefines assert on every inclusion (it doesn't use |
| 30 // include-guards), make sure this is the last file #include'd in this file. | 35 // include-guards), make sure this is the last file #include'd in this file. |
| 31 #undef NDEBUG | 36 #undef NDEBUG |
| 32 #include <assert.h> | 37 #include <assert.h> |
| 33 | 38 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 49 class MyInstance; | 54 class MyInstance; |
| 50 | 55 |
| 51 class MyInstance : public pp::Instance, public pp::Graphics3DClient { | 56 class MyInstance : public pp::Instance, public pp::Graphics3DClient { |
| 52 public: | 57 public: |
| 53 MyInstance(PP_Instance instance, pp::Module* module); | 58 MyInstance(PP_Instance instance, pp::Module* module); |
| 54 virtual ~MyInstance(); | 59 virtual ~MyInstance(); |
| 55 | 60 |
| 56 // pp::Instance implementation. | 61 // pp::Instance implementation. |
| 57 virtual void DidChangeView(const pp::Rect& position, | 62 virtual void DidChangeView(const pp::Rect& position, |
| 58 const pp::Rect& clip_ignored); | 63 const pp::Rect& clip_ignored); |
| 64 virtual bool HandleInputEvent(const pp::InputEvent& event); |
| 59 | 65 |
| 60 // pp::Graphics3DClient implementation. | 66 // pp::Graphics3DClient implementation. |
| 61 virtual void Graphics3DContextLost() { | 67 virtual void Graphics3DContextLost() { |
| 62 // TODO(vrk/fischman): Properly reset after a lost graphics context. In | 68 // TODO(vrk/fischman): Properly reset after a lost graphics context. In |
| 63 // particular need to delete context_ and re-create textures. | 69 // particular need to delete context_ and re-create textures. |
| 64 // Probably have to recreate the decoder from scratch, because old textures | 70 // Probably have to recreate the decoder from scratch, because old textures |
| 65 // can still be outstanding in the decoder! | 71 // can still be outstanding in the decoder! |
| 66 assert(false && "Unexpectedly lost graphics context"); | 72 assert(false && "Unexpectedly lost graphics context"); |
| 67 } | 73 } |
| 68 | 74 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 157 pp::VideoDecoder* decoder_; | 163 pp::VideoDecoder* decoder_; |
| 158 pp::CompletionCallbackFactory<Decoder> callback_factory_; | 164 pp::CompletionCallbackFactory<Decoder> callback_factory_; |
| 159 | 165 |
| 160 size_t encoded_data_next_pos_to_decode_; | 166 size_t encoded_data_next_pos_to_decode_; |
| 161 int next_picture_id_; | 167 int next_picture_id_; |
| 162 int seek_frame_; | 168 int seek_frame_; |
| 163 bool flushing_; | 169 bool flushing_; |
| 164 bool resetting_; | 170 bool resetting_; |
| 165 }; | 171 }; |
| 166 | 172 |
| 173 #if defined(TEST_H264) |
| 167 // Returns true if the current position is at the start of a NAL unit. | 174 // Returns true if the current position is at the start of a NAL unit. |
| 168 static bool LookingAtNAL(const unsigned char* encoded, size_t pos) { | 175 static bool LookingAtNAL(const unsigned char* encoded, size_t pos) { |
| 169 // H264 frames start with 0, 0, 0, 1 in our test data. | 176 // H264 frames start with 0, 0, 0, 1 in our test data. |
| 170 return pos + 3 < kDataLen && encoded[pos] == 0 && encoded[pos + 1] == 0 && | 177 return pos + 3 < kDataLen && encoded[pos] == 0 && encoded[pos + 1] == 0 && |
| 171 encoded[pos + 2] == 0 && encoded[pos + 3] == 1; | 178 encoded[pos + 2] == 0 && encoded[pos + 3] == 1; |
| 172 } | 179 } |
| 180 #endif |
| 173 | 181 |
| 174 // Find the start and end of the next frame. | 182 // Find the start and end of the next frame. |
| 175 static void GetNextFrame(size_t* start_pos, size_t* end_pos) { | 183 static void GetNextFrame(size_t* start_pos, size_t* end_pos) { |
| 184 #if defined(TEST_H264) |
| 176 assert(LookingAtNAL(kData, *start_pos)); | 185 assert(LookingAtNAL(kData, *start_pos)); |
| 177 *end_pos = *start_pos; | 186 *end_pos = *start_pos; |
| 178 *end_pos += 4; | 187 *end_pos += 4; |
| 179 while (*end_pos < kDataLen && !LookingAtNAL(kData, *end_pos)) { | 188 while (*end_pos < kDataLen && !LookingAtNAL(kData, *end_pos)) { |
| 180 ++*end_pos; | 189 ++*end_pos; |
| 181 } | 190 } |
| 191 #elif defined(TEST_VP8) |
| 192 // VP8 is stored in an IVF container. |
| 193 // Helpful description: http://wiki.multimedia.cx/index.php?title=IVF |
| 194 if (*start_pos == 0) |
| 195 *start_pos = 32; // Skip IVF header. |
| 196 uint32_t frame_size = *reinterpret_cast<const uint32_t*>(&kData[*start_pos]); |
| 197 *start_pos += 12; // Skip frame header. |
| 198 *end_pos = *start_pos + frame_size; |
| 199 #endif |
| 182 } | 200 } |
| 183 | 201 |
| 184 Decoder::Decoder(MyInstance* instance, | 202 Decoder::Decoder(MyInstance* instance, |
| 185 int id, | 203 int id, |
| 186 const pp::Graphics3D& graphics_3d) | 204 const pp::Graphics3D& graphics_3d) |
| 187 : instance_(instance), | 205 : instance_(instance), |
| 188 id_(id), | 206 id_(id), |
| 189 decoder_(new pp::VideoDecoder(instance)), | 207 decoder_(new pp::VideoDecoder(instance)), |
| 190 callback_factory_(this), | 208 callback_factory_(this), |
| 191 encoded_data_next_pos_to_decode_(0), | 209 encoded_data_next_pos_to_decode_(0), |
| 192 next_picture_id_(0), | 210 next_picture_id_(0), |
| 193 seek_frame_(0), | 211 seek_frame_(0), |
| 194 flushing_(false), | 212 flushing_(false), |
| 195 resetting_(false) { | 213 resetting_(false) { |
| 196 assert(!decoder_->is_null()); | 214 assert(!decoder_->is_null()); |
| 197 const PP_VideoProfile profile = PP_VIDEOPROFILE_H264MAIN; | 215 const PP_VideoProfile profile = |
| 216 #if defined(TEST_H264) |
| 217 PP_VIDEOPROFILE_H264MAIN; |
| 218 #elif defined(TEST_VP8) |
| 219 PP_VIDEOPROFILE_VP8MAIN; |
| 220 #endif |
| 198 decoder_->Initialize(graphics_3d, | 221 decoder_->Initialize(graphics_3d, |
| 199 profile, | 222 profile, |
| 200 PP_FALSE /* allow_software_fallback */, | 223 PP_TRUE /* allow_software_fallback */, |
| 201 callback_factory_.NewCallback(&Decoder::InitializeDone)); | 224 callback_factory_.NewCallback(&Decoder::InitializeDone)); |
| 202 } | 225 } |
| 203 | 226 |
| 204 Decoder::~Decoder() { | 227 Decoder::~Decoder() { |
| 205 delete decoder_; | 228 delete decoder_; |
| 206 } | 229 } |
| 207 | 230 |
| 208 void Decoder::InitializeDone(int32_t result) { | 231 void Decoder::InitializeDone(int32_t result) { |
| 209 assert(decoder_); | 232 assert(decoder_); |
| 210 assert(result == PP_OK); | 233 assert(result == PP_OK); |
| 211 assert(decoding()); | 234 assert(decoding()); |
| 212 Start(0); | 235 Start(0); |
| 213 } | 236 } |
| 214 | 237 |
| 215 void Decoder::Start(int frame) { | 238 void Decoder::Start(int frame) { |
| 216 assert(decoder_); | 239 assert(decoder_); |
| 217 | 240 |
| 218 // Skip to |frame|. | 241 // Skip to |frame|. |
| 219 size_t start_pos = 0; | 242 size_t start_pos = 0; |
| 220 size_t end_pos = 0; | 243 size_t end_pos = 0; |
| 221 for (int i = 0; i < frame; i++) | 244 for (int i = 0; i < frame; i++) { |
| 222 GetNextFrame(&start_pos, &end_pos); | 245 GetNextFrame(&start_pos, &end_pos); |
| 246 start_pos = end_pos; |
| 247 } |
| 223 encoded_data_next_pos_to_decode_ = end_pos; | 248 encoded_data_next_pos_to_decode_ = end_pos; |
| 249 printf("encoded_data_next_pos_to_decode_=%i\n", (int)encoded_data_next_pos_to_
decode_); |
| 224 | 250 |
| 225 // Register callback to get the first picture. We call GetPicture again in | 251 // Register callback to get the first picture. We call GetPicture again in |
| 226 // PictureReady to continuously receive pictures as they're decoded. | 252 // PictureReady to continuously receive pictures as they're decoded. |
| 227 decoder_->GetPicture( | 253 decoder_->GetPicture( |
| 228 callback_factory_.NewCallbackWithOutput(&Decoder::PictureReady)); | 254 callback_factory_.NewCallbackWithOutput(&Decoder::PictureReady)); |
| 229 | 255 |
| 230 // Start the decode loop. | 256 // Start the decode loop. |
| 231 DecodeNextFrame(); | 257 DecodeNextFrame(); |
| 232 } | 258 } |
| 233 | 259 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 // Break out of the get picture loop on abort. | 309 // Break out of the get picture loop on abort. |
| 284 if (result == PP_ERROR_ABORTED) | 310 if (result == PP_ERROR_ABORTED) |
| 285 return; | 311 return; |
| 286 assert(result == PP_OK); | 312 assert(result == PP_OK); |
| 287 decoder_->GetPicture( | 313 decoder_->GetPicture( |
| 288 callback_factory_.NewCallbackWithOutput(&Decoder::PictureReady)); | 314 callback_factory_.NewCallbackWithOutput(&Decoder::PictureReady)); |
| 289 instance_->PaintPicture(this, picture); | 315 instance_->PaintPicture(this, picture); |
| 290 } | 316 } |
| 291 | 317 |
| 292 void Decoder::FlushDone(int32_t result) { | 318 void Decoder::FlushDone(int32_t result) { |
| 319 printf("FlushDone:result=%i\n", result); |
| 293 assert(decoder_); | 320 assert(decoder_); |
| 294 assert(result == PP_OK || result == PP_ERROR_ABORTED); | 321 assert(result == PP_OK || result == PP_ERROR_ABORTED); |
| 295 flushing_ = false; | 322 flushing_ = false; |
| 296 } | 323 } |
| 297 | 324 |
| 298 void Decoder::ResetDone(int32_t result) { | 325 void Decoder::ResetDone(int32_t result) { |
| 326 printf("ResetDone:result=%i\n", result); |
| 299 assert(decoder_); | 327 assert(decoder_); |
| 300 assert(result == PP_OK); | 328 assert(result == PP_OK); |
| 301 resetting_ = false; | 329 resetting_ = false; |
| 330 |
| 331 Start(seek_frame_); |
| 302 } | 332 } |
| 303 | 333 |
| 304 MyInstance::MyInstance(PP_Instance instance, pp::Module* module) | 334 MyInstance::MyInstance(PP_Instance instance, pp::Module* module) |
| 305 : pp::Instance(instance), | 335 : pp::Instance(instance), |
| 306 pp::Graphics3DClient(this), | 336 pp::Graphics3DClient(this), |
| 307 is_painting_(false), | 337 is_painting_(false), |
| 308 num_frames_rendered_(0), | 338 num_frames_rendered_(0), |
| 309 first_frame_delivered_ticks_(-1), | 339 first_frame_delivered_ticks_(-1), |
| 310 last_swap_request_ticks_(-1), | 340 last_swap_request_ticks_(-1), |
| 311 swap_ticks_(0), | 341 swap_ticks_(0), |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 assert(position.size() == plugin_size_); | 376 assert(position.size() == plugin_size_); |
| 347 return; | 377 return; |
| 348 } | 378 } |
| 349 plugin_size_ = position.size(); | 379 plugin_size_ = position.size(); |
| 350 | 380 |
| 351 // Initialize graphics. | 381 // Initialize graphics. |
| 352 InitGL(); | 382 InitGL(); |
| 353 InitializeDecoders(); | 383 InitializeDecoders(); |
| 354 } | 384 } |
| 355 | 385 |
| 386 bool MyInstance::HandleInputEvent(const pp::InputEvent& event) { |
| 387 switch (event.GetType()) { |
| 388 case PP_INPUTEVENT_TYPE_MOUSEDOWN: { |
| 389 pp::MouseInputEvent mouse_event(event); |
| 390 // Reset all decoders and restart video at a point proportional to the |
| 391 // mouse's horiziontal offset from the left edge of the plugin area. |
| 392 if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT) { |
| 393 pp::Point mouse_position = mouse_event.GetPosition(); |
| 394 const int num_frames = 300; // TODO figure out real number of frames. |
| 395 int frame = |
| 396 (float)mouse_position.x() / plugin_size_.width() * num_frames; |
| 397 for (size_t i = 0; i < video_decoders_.size(); i++) { |
| 398 video_decoders_[i]->Seek(frame); |
| 399 } |
| 400 printf("Seeking:frame=%i\n", frame); |
| 401 } |
| 402 return true; |
| 403 } |
| 404 |
| 405 default: |
| 406 return false; |
| 407 } |
| 408 } |
| 409 |
| 356 void MyInstance::InitializeDecoders() { | 410 void MyInstance::InitializeDecoders() { |
| 357 assert(video_decoders_.empty()); | 411 assert(video_decoders_.empty()); |
| 358 // Create two decoders with ids 0 and 1. | 412 // Create two decoders with ids 0 and 1. |
| 359 video_decoders_.push_back(new Decoder(this, 0, *context_)); | 413 video_decoders_.push_back(new Decoder(this, 0, *context_)); |
| 360 video_decoders_.push_back(new Decoder(this, 1, *context_)); | 414 video_decoders_.push_back(new Decoder(this, 1, *context_)); |
| 361 } | 415 } |
| 362 | 416 |
| 363 void MyInstance::PaintPicture(Decoder* decoder, | 417 void MyInstance::PaintPicture(Decoder* decoder, |
| 364 const PP_VideoPicture& picture) { | 418 const PP_VideoPicture& picture) { |
| 365 if (first_frame_delivered_ticks_ == -1) | 419 if (first_frame_delivered_ticks_ == -1) |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 }; | 654 }; |
| 601 | 655 |
| 602 } // anonymous namespace | 656 } // anonymous namespace |
| 603 | 657 |
| 604 namespace pp { | 658 namespace pp { |
| 605 // Factory function for your specialization of the Module object. | 659 // Factory function for your specialization of the Module object. |
| 606 Module* CreateModule() { | 660 Module* CreateModule() { |
| 607 return new MyModule(); | 661 return new MyModule(); |
| 608 } | 662 } |
| 609 } // namespace pp | 663 } // namespace pp |
| OLD | NEW |