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 // VP8 is more likely to work on different versions of Chrome. Undefine this | |
25 // to decode H264. | |
26 #define USE_VP8_TESTDATA_INSTEAD_OF_H264 | |
27 #include "ppapi/examples/video_decode/testdata.h" | 23 #include "ppapi/examples/video_decode/testdata.h" |
28 | |
29 #include "ppapi/lib/gl/include/GLES2/gl2.h" | 24 #include "ppapi/lib/gl/include/GLES2/gl2.h" |
30 #include "ppapi/lib/gl/include/GLES2/gl2ext.h" | 25 #include "ppapi/lib/gl/include/GLES2/gl2ext.h" |
31 #include "ppapi/utility/completion_callback_factory.h" | 26 #include "ppapi/utility/completion_callback_factory.h" |
32 | 27 |
33 // Use assert as a poor-man's CHECK, even in non-debug mode. | 28 // Use assert as a poor-man's CHECK, even in non-debug mode. |
34 // Since <assert.h> redefines assert on every inclusion (it doesn't use | 29 // Since <assert.h> redefines assert on every inclusion (it doesn't use |
35 // include-guards), make sure this is the last file #include'd in this file. | 30 // include-guards), make sure this is the last file #include'd in this file. |
36 #undef NDEBUG | 31 #undef NDEBUG |
37 #include <assert.h> | 32 #include <assert.h> |
38 | 33 |
(...skipping 15 matching lines...) Expand all Loading... |
54 class MyInstance; | 49 class MyInstance; |
55 | 50 |
56 class MyInstance : public pp::Instance, public pp::Graphics3DClient { | 51 class MyInstance : public pp::Instance, public pp::Graphics3DClient { |
57 public: | 52 public: |
58 MyInstance(PP_Instance instance, pp::Module* module); | 53 MyInstance(PP_Instance instance, pp::Module* module); |
59 virtual ~MyInstance(); | 54 virtual ~MyInstance(); |
60 | 55 |
61 // pp::Instance implementation. | 56 // pp::Instance implementation. |
62 virtual void DidChangeView(const pp::Rect& position, | 57 virtual void DidChangeView(const pp::Rect& position, |
63 const pp::Rect& clip_ignored); | 58 const pp::Rect& clip_ignored); |
64 virtual bool HandleInputEvent(const pp::InputEvent& event); | |
65 | 59 |
66 // pp::Graphics3DClient implementation. | 60 // pp::Graphics3DClient implementation. |
67 virtual void Graphics3DContextLost() { | 61 virtual void Graphics3DContextLost() { |
68 // TODO(vrk/fischman): Properly reset after a lost graphics context. In | 62 // TODO(vrk/fischman): Properly reset after a lost graphics context. In |
69 // particular need to delete context_ and re-create textures. | 63 // particular need to delete context_ and re-create textures. |
70 // Probably have to recreate the decoder from scratch, because old textures | 64 // Probably have to recreate the decoder from scratch, because old textures |
71 // can still be outstanding in the decoder! | 65 // can still be outstanding in the decoder! |
72 assert(false && "Unexpectedly lost graphics context"); | 66 assert(false && "Unexpectedly lost graphics context"); |
73 } | 67 } |
74 | 68 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 }; | 132 }; |
139 | 133 |
140 class Decoder { | 134 class Decoder { |
141 public: | 135 public: |
142 Decoder(MyInstance* instance, int id, const pp::Graphics3D& graphics_3d); | 136 Decoder(MyInstance* instance, int id, const pp::Graphics3D& graphics_3d); |
143 ~Decoder(); | 137 ~Decoder(); |
144 | 138 |
145 int id() const { return id_; } | 139 int id() const { return id_; } |
146 bool decoding() const { return !flushing_ && !resetting_; } | 140 bool decoding() const { return !flushing_ && !resetting_; } |
147 | 141 |
148 void Reset(); | 142 void Seek(int frame); |
149 void RecyclePicture(const PP_VideoPicture& picture); | 143 void RecyclePicture(const PP_VideoPicture& picture); |
150 | 144 |
151 private: | 145 private: |
152 void InitializeDone(int32_t result); | 146 void InitializeDone(int32_t result); |
153 void Start(); | 147 void Start(int frame); |
154 void DecodeNextFrame(); | 148 void DecodeNextFrame(); |
155 void DecodeDone(int32_t result); | 149 void DecodeDone(int32_t result); |
156 void PictureReady(int32_t result, PP_VideoPicture picture); | 150 void PictureReady(int32_t result, PP_VideoPicture picture); |
157 void FlushDone(int32_t result); | 151 void FlushDone(int32_t result); |
158 void ResetDone(int32_t result); | 152 void ResetDone(int32_t result); |
159 | 153 |
160 MyInstance* instance_; | 154 MyInstance* instance_; |
161 int id_; | 155 int id_; |
162 | 156 |
163 pp::VideoDecoder* decoder_; | 157 pp::VideoDecoder* decoder_; |
164 pp::CompletionCallbackFactory<Decoder> callback_factory_; | 158 pp::CompletionCallbackFactory<Decoder> callback_factory_; |
165 | 159 |
166 size_t encoded_data_next_pos_to_decode_; | 160 size_t encoded_data_next_pos_to_decode_; |
167 int next_picture_id_; | 161 int next_picture_id_; |
| 162 int seek_frame_; |
168 bool flushing_; | 163 bool flushing_; |
169 bool resetting_; | 164 bool resetting_; |
170 }; | 165 }; |
171 | 166 |
172 #if defined USE_VP8_TESTDATA_INSTEAD_OF_H264 | |
173 | |
174 // VP8 is stored in an IVF container. | |
175 // Helpful description: http://wiki.multimedia.cx/index.php?title=IVF | |
176 | |
177 static void GetNextFrame(size_t* start_pos, size_t* end_pos) { | |
178 size_t current_pos = *start_pos; | |
179 if (current_pos == 0) | |
180 current_pos = 32; // Skip stream header. | |
181 uint32_t frame_size = kData[current_pos] + (kData[current_pos + 1] << 8) + | |
182 (kData[current_pos + 2] << 16) + | |
183 (kData[current_pos + 3] << 24); | |
184 current_pos += 12; // Skip frame header. | |
185 *start_pos = current_pos; | |
186 *end_pos = current_pos + frame_size; | |
187 } | |
188 | |
189 #else // !USE_VP8_TESTDATA_INSTEAD_OF_H264 | |
190 | |
191 // Returns true if the current position is at the start of a NAL unit. | 167 // Returns true if the current position is at the start of a NAL unit. |
192 static bool LookingAtNAL(const unsigned char* encoded, size_t pos) { | 168 static bool LookingAtNAL(const unsigned char* encoded, size_t pos) { |
193 // H264 frames start with 0, 0, 0, 1 in our test data. | 169 // H264 frames start with 0, 0, 0, 1 in our test data. |
194 return pos + 3 < kDataLen && encoded[pos] == 0 && encoded[pos + 1] == 0 && | 170 return pos + 3 < kDataLen && encoded[pos] == 0 && encoded[pos + 1] == 0 && |
195 encoded[pos + 2] == 0 && encoded[pos + 3] == 1; | 171 encoded[pos + 2] == 0 && encoded[pos + 3] == 1; |
196 } | 172 } |
197 | 173 |
| 174 // Find the start and end of the next frame. |
198 static void GetNextFrame(size_t* start_pos, size_t* end_pos) { | 175 static void GetNextFrame(size_t* start_pos, size_t* end_pos) { |
199 assert(LookingAtNAL(kData, *start_pos)); | 176 assert(LookingAtNAL(kData, *start_pos)); |
200 *end_pos = *start_pos; | 177 *end_pos = *start_pos; |
201 *end_pos += 4; | 178 *end_pos += 4; |
202 while (*end_pos < kDataLen && !LookingAtNAL(kData, *end_pos)) { | 179 while (*end_pos < kDataLen && !LookingAtNAL(kData, *end_pos)) { |
203 ++*end_pos; | 180 ++*end_pos; |
204 } | 181 } |
205 } | 182 } |
206 | 183 |
207 #endif // USE_VP8_TESTDATA_INSTEAD_OF_H264 | |
208 | |
209 Decoder::Decoder(MyInstance* instance, | 184 Decoder::Decoder(MyInstance* instance, |
210 int id, | 185 int id, |
211 const pp::Graphics3D& graphics_3d) | 186 const pp::Graphics3D& graphics_3d) |
212 : instance_(instance), | 187 : instance_(instance), |
213 id_(id), | 188 id_(id), |
214 decoder_(new pp::VideoDecoder(instance)), | 189 decoder_(new pp::VideoDecoder(instance)), |
215 callback_factory_(this), | 190 callback_factory_(this), |
216 encoded_data_next_pos_to_decode_(0), | 191 encoded_data_next_pos_to_decode_(0), |
217 next_picture_id_(0), | 192 next_picture_id_(0), |
| 193 seek_frame_(0), |
218 flushing_(false), | 194 flushing_(false), |
219 resetting_(false) { | 195 resetting_(false) { |
220 // TODO(bbudge) Remove this for final patch. | |
221 #if defined USE_VP8_TESTDATA_INSTEAD_OF_H264 | |
222 const PP_VideoProfile kBitstreamProfile = PP_VIDEOPROFILE_VP8MAIN; | |
223 #else | |
224 const PP_VideoProfile kBitstreamProfile = PP_VIDEOPROFILE_H264MAIN; | |
225 #endif | |
226 | |
227 assert(!decoder_->is_null()); | 196 assert(!decoder_->is_null()); |
| 197 const PP_VideoProfile profile = PP_VIDEOPROFILE_H264MAIN; |
228 decoder_->Initialize(graphics_3d, | 198 decoder_->Initialize(graphics_3d, |
229 kBitstreamProfile, | 199 profile, |
230 PP_TRUE /* allow_software_fallback */, | 200 PP_FALSE /* allow_software_fallback */, |
231 callback_factory_.NewCallback(&Decoder::InitializeDone)); | 201 callback_factory_.NewCallback(&Decoder::InitializeDone)); |
232 } | 202 } |
233 | 203 |
234 Decoder::~Decoder() { | 204 Decoder::~Decoder() { |
235 delete decoder_; | 205 delete decoder_; |
236 } | 206 } |
237 | 207 |
238 void Decoder::InitializeDone(int32_t result) { | 208 void Decoder::InitializeDone(int32_t result) { |
239 assert(decoder_); | 209 assert(decoder_); |
240 assert(result == PP_OK); | 210 assert(result == PP_OK); |
241 assert(decoding()); | 211 assert(decoding()); |
242 Start(); | 212 Start(0); |
243 } | 213 } |
244 | 214 |
245 void Decoder::Start() { | 215 void Decoder::Start(int frame) { |
246 assert(decoder_); | 216 assert(decoder_); |
247 | 217 |
248 encoded_data_next_pos_to_decode_ = 0; | 218 // Skip to |frame|. |
| 219 size_t start_pos = 0; |
| 220 size_t end_pos = 0; |
| 221 for (int i = 0; i < frame; i++) |
| 222 GetNextFrame(&start_pos, &end_pos); |
| 223 encoded_data_next_pos_to_decode_ = end_pos; |
249 | 224 |
250 // Register callback to get the first picture. We call GetPicture again in | 225 // Register callback to get the first picture. We call GetPicture again in |
251 // PictureReady to continuously receive pictures as they're decoded. | 226 // PictureReady to continuously receive pictures as they're decoded. |
252 decoder_->GetPicture( | 227 decoder_->GetPicture( |
253 callback_factory_.NewCallbackWithOutput(&Decoder::PictureReady)); | 228 callback_factory_.NewCallbackWithOutput(&Decoder::PictureReady)); |
254 | 229 |
255 // Start the decode loop. | 230 // Start the decode loop. |
256 DecodeNextFrame(); | 231 DecodeNextFrame(); |
257 } | 232 } |
258 | 233 |
259 void Decoder::Reset() { | 234 void Decoder::Seek(int frame) { |
260 assert(decoder_); | 235 assert(decoder_); |
| 236 seek_frame_ = frame; |
261 resetting_ = true; | 237 resetting_ = true; |
262 decoder_->Reset(callback_factory_.NewCallback(&Decoder::ResetDone)); | 238 decoder_->Reset(callback_factory_.NewCallback(&Decoder::ResetDone)); |
263 } | 239 } |
264 | 240 |
265 void Decoder::RecyclePicture(const PP_VideoPicture& picture) { | 241 void Decoder::RecyclePicture(const PP_VideoPicture& picture) { |
266 assert(decoder_); | 242 assert(decoder_); |
267 decoder_->RecyclePicture(picture); | 243 decoder_->RecyclePicture(picture); |
268 } | 244 } |
269 | 245 |
270 void Decoder::DecodeNextFrame() { | 246 void Decoder::DecodeNextFrame() { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 void Decoder::FlushDone(int32_t result) { | 292 void Decoder::FlushDone(int32_t result) { |
317 assert(decoder_); | 293 assert(decoder_); |
318 assert(result == PP_OK || result == PP_ERROR_ABORTED); | 294 assert(result == PP_OK || result == PP_ERROR_ABORTED); |
319 flushing_ = false; | 295 flushing_ = false; |
320 } | 296 } |
321 | 297 |
322 void Decoder::ResetDone(int32_t result) { | 298 void Decoder::ResetDone(int32_t result) { |
323 assert(decoder_); | 299 assert(decoder_); |
324 assert(result == PP_OK); | 300 assert(result == PP_OK); |
325 resetting_ = false; | 301 resetting_ = false; |
326 | |
327 Start(); | |
328 } | 302 } |
329 | 303 |
330 MyInstance::MyInstance(PP_Instance instance, pp::Module* module) | 304 MyInstance::MyInstance(PP_Instance instance, pp::Module* module) |
331 : pp::Instance(instance), | 305 : pp::Instance(instance), |
332 pp::Graphics3DClient(this), | 306 pp::Graphics3DClient(this), |
333 is_painting_(false), | 307 is_painting_(false), |
334 num_frames_rendered_(0), | 308 num_frames_rendered_(0), |
335 first_frame_delivered_ticks_(-1), | 309 first_frame_delivered_ticks_(-1), |
336 last_swap_request_ticks_(-1), | 310 last_swap_request_ticks_(-1), |
337 swap_ticks_(0), | 311 swap_ticks_(0), |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
372 assert(position.size() == plugin_size_); | 346 assert(position.size() == plugin_size_); |
373 return; | 347 return; |
374 } | 348 } |
375 plugin_size_ = position.size(); | 349 plugin_size_ = position.size(); |
376 | 350 |
377 // Initialize graphics. | 351 // Initialize graphics. |
378 InitGL(); | 352 InitGL(); |
379 InitializeDecoders(); | 353 InitializeDecoders(); |
380 } | 354 } |
381 | 355 |
382 bool MyInstance::HandleInputEvent(const pp::InputEvent& event) { | |
383 switch (event.GetType()) { | |
384 case PP_INPUTEVENT_TYPE_MOUSEDOWN: { | |
385 pp::MouseInputEvent mouse_event(event); | |
386 // Reset all decoders on mouse down. | |
387 if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT) { | |
388 for (size_t i = 0; i < video_decoders_.size(); i++) { | |
389 if (video_decoders_[i]->decoding()) | |
390 video_decoders_[i]->Reset(); | |
391 } | |
392 } | |
393 return true; | |
394 } | |
395 | |
396 default: | |
397 return false; | |
398 } | |
399 } | |
400 | |
401 void MyInstance::InitializeDecoders() { | 356 void MyInstance::InitializeDecoders() { |
402 assert(video_decoders_.empty()); | 357 assert(video_decoders_.empty()); |
403 // Create two decoders with ids 0 and 1. | 358 // Create two decoders with ids 0 and 1. |
404 video_decoders_.push_back(new Decoder(this, 0, *context_)); | 359 video_decoders_.push_back(new Decoder(this, 0, *context_)); |
405 video_decoders_.push_back(new Decoder(this, 1, *context_)); | 360 video_decoders_.push_back(new Decoder(this, 1, *context_)); |
406 } | 361 } |
407 | 362 |
408 void MyInstance::PaintPicture(Decoder* decoder, | 363 void MyInstance::PaintPicture(Decoder* decoder, |
409 const PP_VideoPicture& picture) { | 364 const PP_VideoPicture& picture) { |
410 if (first_frame_delivered_ticks_ == -1) | 365 if (first_frame_delivered_ticks_ == -1) |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
645 }; | 600 }; |
646 | 601 |
647 } // anonymous namespace | 602 } // anonymous namespace |
648 | 603 |
649 namespace pp { | 604 namespace pp { |
650 // Factory function for your specialization of the Module object. | 605 // Factory function for your specialization of the Module object. |
651 Module* CreateModule() { | 606 Module* CreateModule() { |
652 return new MyModule(); | 607 return new MyModule(); |
653 } | 608 } |
654 } // namespace pp | 609 } // namespace pp |
OLD | NEW |