Panda3D
movieTexture.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file movieTexture.cxx
10  * @author jyelon
11  * @date 2007-08-01
12  */
13 
14 #include "pandabase.h"
15 
16 #ifdef HAVE_AUDIO
17 
18 #include "movieVideo.h"
19 #include "movieVideoCursor.h"
20 #include "movieTypeRegistry.h"
21 #include "movieTexture.h"
22 #include "clockObject.h"
23 #include "config_gobj.h"
24 #include "config_grutil.h"
25 #include "bamCacheRecord.h"
26 #include "bamReader.h"
27 #include "bamWriter.h"
28 #include "audioSound.h"
29 
30 #include <math.h>
31 
32 TypeHandle MovieTexture::_type_handle;
33 
34 /**
35  * Creates a blank movie texture. Movies must be added using do_read_one or
36  * do_load_one.
37  */
38 MovieTexture::
39 MovieTexture(const std::string &name) :
40  Texture(name)
41 {
42 }
43 
44 /**
45  * Creates a texture playing the specified movie.
46  */
47 MovieTexture::
48 MovieTexture(MovieVideo *video) :
49  Texture(video->get_name())
50 {
51  Texture::CDWriter cdata_tex(Texture::_cycler, true);
52  do_load_one(cdata_tex, video->open(), nullptr, 0, LoaderOptions());
53 }
54 
55 /**
56  * xxx
57  */
58 MovieTexture::CData::
59 CData() :
60  _video_width(1),
61  _video_height(1),
62  _video_length(1.0),
63  _clock(0.0),
64  _playing(false),
65  _loop_count(1),
66  _play_rate(1.0),
67  _has_offset(false)
68 {
69 }
70 
71 /**
72  * xxx
73  */
74 MovieTexture::CData::
75 CData(const CData &copy) :
76  _pages(copy._pages),
77  _video_width(copy._video_width),
78  _video_height(copy._video_height),
79  _video_length(copy._video_length),
80  _clock(0.0),
81  _playing(false),
82  _loop_count(1),
83  _play_rate(1.0),
84  _has_offset(false)
85 {
86 }
87 
88 /**
89  * xxx
90  */
91 CycleData *MovieTexture::CData::
92 make_copy() const {
93  return new CData(*this);
94 }
95 
96 /**
97  * xxx
98  */
99 MovieTexture::
100 ~MovieTexture() {
101  clear();
102 }
103 
104 /**
105  * May be called prior to calling read_txo() or any bam-related Texture-
106  * creating callback, to ensure that the proper dynamic libraries for a
107  * Texture of the current class type, and the indicated filename, have been
108  * already loaded.
109  *
110  * This is a low-level function that should not normally need to be called
111  * directly by the user.
112  *
113  * Note that for best results you must first create a Texture object of the
114  * appropriate class type for your filename, for instance with
115  * TexturePool::make_texture().
116  */
117 void MovieTexture::
118 ensure_loader_type(const Filename &filename) {
119  // Creating a MovieVideo of the appropriate type is a slightly hacky way to
120  // ensure the appropriate libraries are loaded. We can let the MovieVideo
121  // we create immediately destruct.
123  PT(MovieVideo) video = reg->make_video(filename);
124 }
125 
126 /**
127  * A factory function to make a new MovieTexture, used to pass to the
128  * TexturePool.
129  */
130 PT(Texture) MovieTexture::
131 make_texture() {
132  return new MovieTexture("");
133 }
134 
135 /**
136  * Resizes the texture, and adjusts the format, based on the source movies.
137  * The resulting texture will be large enough to hold all the videos.
138  *
139  * Assumes the lock is already held.
140  */
141 void MovieTexture::
142 do_recalculate_image_properties(CData *cdata, Texture::CData *cdata_tex, const LoaderOptions &options) {
143  int x_max = 1;
144  int y_max = 1;
145  bool rgb = false;
146  bool alpha = false;
147  double len = 0.0;
148 
149  for (size_t i = 0; i < cdata->_pages.size(); ++i) {
150  MovieVideoCursor *t = cdata->_pages[i]._color;
151  if (t) {
152  if (t->size_x() > x_max) x_max = t->size_x();
153  if (t->size_y() > y_max) y_max = t->size_y();
154  if (t->length() > len) len = t->length();
155  if (t->get_num_components() >= 3) rgb=true;
156  if (t->get_num_components() == 4 || t->get_num_components() == 2) alpha=true;
157  }
158  t = cdata->_pages[i]._alpha;
159  if (t) {
160  if (t->size_x() > x_max) x_max = t->size_x();
161  if (t->size_y() > y_max) y_max = t->size_y();
162  if (t->length() > len) len = t->length();
163  alpha = true;
164  }
165  }
166 
167  cdata->_video_width = x_max;
168  cdata->_video_height = y_max;
169  cdata->_video_length = len;
170 
171  do_adjust_this_size(cdata_tex, x_max, y_max, get_name(), true);
172 
173  int num_components = (rgb ? 3 : 1) + alpha;
174  do_reconsider_image_properties(cdata_tex, x_max, y_max, num_components,
175  T_unsigned_byte, cdata->_pages.size(),
176  options);
177  cdata_tex->_orig_file_x_size = cdata->_video_width;
178  cdata_tex->_orig_file_y_size = cdata->_video_height;
179 
180  do_set_pad_size(cdata_tex,
181  std::max(cdata_tex->_x_size - cdata_tex->_orig_file_x_size, 0),
182  std::max(cdata_tex->_y_size - cdata_tex->_orig_file_y_size, 0),
183  0);
184 }
185 
186 /**
187  * Works like adjust_size, but also considers the texture class. Movie
188  * textures, for instance, always pad outwards, never scale down.
189  */
190 bool MovieTexture::
191 do_adjust_this_size(const Texture::CData *cdata_tex,
192  int &x_size, int &y_size, const std::string &name,
193  bool for_padding) const {
194  AutoTextureScale ats = do_get_auto_texture_scale(cdata_tex);
195  if (ats != ATS_none) {
196  ats = ATS_pad;
197  }
198 
199  return adjust_size(x_size, y_size, name, for_padding, ats);
200 }
201 
202 /**
203  * Combines a color and alpha video image from the two indicated filenames.
204  * Both must be the same kind of video with similar properties.
205  */
206 bool MovieTexture::
207 do_read_one(Texture::CData *cdata_tex,
208  const Filename &fullpath, const Filename &alpha_fullpath,
209  int z, int n, int primary_file_num_channels, int alpha_file_channel,
210  const LoaderOptions &options,
211  bool header_only, BamCacheRecord *record) {
212  nassertr(n == 0, false);
213  if (!do_reconsider_z_size(cdata_tex, z, options)) {
214  return false;
215  }
216  nassertr(z >= 0 && z < cdata_tex->_z_size * cdata_tex->_num_views, false);
217 
218  if (record != nullptr) {
219  record->add_dependent_file(fullpath);
220  }
221 
222  PT(MovieVideoCursor) color;
223  PT(MovieVideoCursor) alpha;
224 
225  color = MovieVideo::get(fullpath)->open();
226  if (color == nullptr) {
227  return false;
228  }
229  if (!alpha_fullpath.empty()) {
230  alpha = MovieVideo::get(alpha_fullpath)->open();
231  if (alpha == nullptr) {
232  return false;
233  }
234  }
235 
236  if (z == 0) {
237  if (!has_name()) {
238  set_name(fullpath.get_basename_wo_extension());
239  }
240  // Don't use has_filename() here, it will cause a deadlock
241  if (cdata_tex->_filename.empty()) {
242  cdata_tex->_filename = fullpath;
243  cdata_tex->_alpha_filename = alpha_fullpath;
244  }
245 
246  cdata_tex->_fullpath = fullpath;
247  cdata_tex->_alpha_fullpath = alpha_fullpath;
248  }
249 
250  cdata_tex->_primary_file_num_channels = primary_file_num_channels;
251  cdata_tex->_alpha_file_channel = alpha_file_channel;
252 
253  if (!do_load_one(cdata_tex, color, alpha, z, options)) {
254  return false;
255  }
256 
257  cdata_tex->_loaded_from_image = true;
258  set_loop(true);
259  play();
260  return true;
261 }
262 
263 /**
264  * Loads movie objects into the texture.
265  */
266 bool MovieTexture::
267 do_load_one(Texture::CData *cdata_tex,
268  PT(MovieVideoCursor) color, PT(MovieVideoCursor) alpha, int z,
269  const LoaderOptions &options) {
270  CDWriter cdata(_cycler);
271  cdata->_pages.resize(z + 1);
272  cdata->_pages[z]._color = color;
273  cdata->_pages[z]._alpha = alpha;
274  do_recalculate_image_properties(cdata, cdata_tex, options);
275 
276  // Make sure the image data is initially black, which is nice for padded
277  // textures.
278  PTA_uchar image = make_ram_image();
279  memset(image.p(), 0, image.size());
280 
281  return true;
282 }
283 
284 /**
285  * Loading a static image into a MovieTexture is an error.
286  */
287 bool MovieTexture::
288 do_load_one(Texture::CData *cdata_tex,
289  const PNMImage &pnmimage, const std::string &name, int z, int n,
290  const LoaderOptions &options) {
291  grutil_cat.error() << "You cannot load a static image into a MovieTexture\n";
292  return false;
293 }
294 
295 /**
296  * Loading a static image into a MovieTexture is an error.
297  */
298 bool MovieTexture::
299 do_load_one(Texture::CData *cdata_tex,
300  const PfmFile &pfm, const std::string &name, int z, int n,
301  const LoaderOptions &options) {
302  grutil_cat.error() << "You cannot load a static image into a MovieTexture\n";
303  return false;
304 }
305 
306 /**
307  * Called internally by do_reconsider_z_size() to allocate new memory in
308  * _ram_images[0] for the new number of pages.
309  *
310  * Assumes the lock is already held.
311  */
312 void MovieTexture::
313 do_allocate_pages(Texture::CData *cdata_tex) {
314  // We don't actually do anything here; the allocation is made in
315  // do_load_one(), above.
316 }
317 
318 /**
319  * Should be overridden by derived classes to return true if cull_callback()
320  * has been defined. Otherwise, returns false to indicate cull_callback()
321  * does not need to be called for this node during the cull traversal.
322  */
323 bool MovieTexture::
324 has_cull_callback() const {
325  return true;
326 }
327 
328 /**
329  * This function will be called during the cull traversal to update the
330  * MovieTexture. This update consists of fetching the next video frame from
331  * the underlying MovieVideo sources. The MovieVideo object belongs to the
332  * cull thread.
333  */
334 bool MovieTexture::
335 cull_callback(CullTraverser *, const CullTraverserData &) const {
336  Texture::CDReader cdata_tex(Texture::_cycler);
337  CDReader cdata(_cycler);
338 
339  if (!cdata->_has_offset) {
340  // If we don't have a previously-computed timestamp (offset) cached, then
341  // compute a new one.
342  double offset;
343  int true_loop_count = 1;
344  if (cdata->_synchronize != nullptr) {
345  offset = cdata->_synchronize->get_time();
346  } else {
347  // Calculate the cursor position modulo the length of the movie.
349  offset = cdata->_clock;
350  if (cdata->_playing) {
351  offset += now * cdata->_play_rate;
352  }
353  true_loop_count = cdata->_loop_count;
354  }
355  ((CData *)cdata.p())->_offset = offset;
356  ((CData *)cdata.p())->_true_loop_count = true_loop_count;
357  ((CData *)cdata.p())->_has_offset = true;
358  }
359 
360  bool in_sync = do_update_frames(cdata);
361  if (!in_sync) {
362  // If it didn't successfully sync, try again--once. The second time it
363  // might be able to fill in some more recent frames.
364  in_sync = do_update_frames(cdata);
365  }
366 
367  if (in_sync) {
368  // Now go back through and apply all the frames to the texture.
369  Pages::const_iterator pi;
370  for (pi = cdata->_pages.begin(); pi != cdata->_pages.end(); ++pi) {
371  const VideoPage &page = (*pi);
372  MovieVideoCursor *color = page._color;
373  MovieVideoCursor *alpha = page._alpha;
374  size_t i = pi - cdata->_pages.begin();
375 
376  if (color != nullptr && alpha != nullptr) {
377  color->apply_to_texture_rgb(page._cbuffer, (MovieTexture*)this, i);
378  alpha->apply_to_texture_alpha(page._abuffer, (MovieTexture*)this, i, cdata_tex->_alpha_file_channel);
379 
380  } else if (color != nullptr) {
381  color->apply_to_texture(page._cbuffer, (MovieTexture*)this, i);
382  }
383 
384  ((VideoPage &)page)._cbuffer.clear();
385  ((VideoPage &)page)._abuffer.clear();
386  }
387 
388  // Clear the cached offset so we can update the frame next time.
389  ((CData *)cdata.p())->_has_offset = false;
390  }
391 
392  return true;
393 }
394 
395 /**
396  * Returns a new copy of the same Texture. This copy, if applied to geometry,
397  * will be copied into texture as a separate texture from the original, so it
398  * will be duplicated in texture memory (and may be independently modified if
399  * desired).
400  *
401  * If the Texture is a MovieTexture, the resulting duplicate may be animated
402  * independently of the original.
403  */
404 PT(Texture) MovieTexture::
405 make_copy_impl() const {
406  Texture::CDReader cdata_tex(Texture::_cycler);
407  CDReader cdata(_cycler);
408  PT(MovieTexture) copy = new MovieTexture(get_name());
409  Texture::CDWriter cdata_copy_tex(copy->Texture::_cycler, true);
410  CDWriter cdata_copy(copy->_cycler, true);
411  copy->do_assign(cdata_copy, cdata_copy_tex, this, cdata, cdata_tex);
412 
413  return copy;
414 }
415 
416 /**
417  * Implements make_copy().
418  */
419 void MovieTexture::
420 do_assign(CData *cdata, Texture::CData *cdata_tex, const MovieTexture *copy,
421  const CData *cdata_copy, const Texture::CData *cdata_copy_tex) {
422  Texture::do_assign(cdata_tex, copy, cdata_copy_tex);
423 
426  color.resize(cdata_copy->_pages.size());
427  alpha.resize(cdata_copy->_pages.size());
428  for (int i=0; i<(int)(color.size()); i++) {
429  color[i] = cdata_copy->_pages[i]._color;
430  alpha[i] = cdata_copy->_pages[i]._alpha;
431  }
432 
433  cdata->_pages.resize(color.size());
434  for (int i=0; i<(int)(color.size()); i++) {
435  if (color[i]) {
436  cdata->_pages[i]._color = color[i]->get_source()->open();
437  }
438  if (alpha[i]) {
439  cdata->_pages[i]._alpha = alpha[i]->get_source()->open();
440  }
441  }
442  do_recalculate_image_properties(cdata, cdata_tex, LoaderOptions());
443 }
444 
445 /**
446  * A MovieTexture must always keep its ram image, since there is no way to
447  * reload it from the source MovieVideo.
448  */
449 void MovieTexture::
450 do_reload_ram_image(Texture::CData *cdata, bool allow_compression) {
451  // A MovieTexture should never dump its RAM image. Therefore, this is not
452  // needed.
453 }
454 
455 /**
456  * A MovieTexture must always keep its ram image, since there is no way to
457  * reload it from the source MovieVideo.
458  */
459 bool MovieTexture::
460 get_keep_ram_image() const {
461  // A MovieTexture should never dump its RAM image.
462  return true;
463 }
464 
465 /**
466  * Returns true if there is a rawdata image that we have available to write to
467  * the bam stream. For a normal Texture, this is the same thing as
468  * do_has_ram_image(), but a movie texture might define it differently.
469  */
470 bool MovieTexture::
471 do_has_bam_rawdata(const Texture::CData *cdata) const {
472  return true;
473 }
474 
475 /**
476  * If do_has_bam_rawdata() returned false, this attempts to reload the rawdata
477  * image if possible.
478  */
479 void MovieTexture::
480 do_get_bam_rawdata(Texture::CData *cdata) {
481 }
482 
483 /**
484  * Returns true if we can safely call do_unlock_and_reload_ram_image() in
485  * order to make the image available, or false if we shouldn't do this
486  * (because we know from a priori knowledge that it wouldn't work anyway).
487  */
488 bool MovieTexture::
489 do_can_reload(const Texture::CData *cdata) const {
490  return false;
491 }
492 
493 /**
494  * Start playing the movie from where it was last paused. Has no effect if
495  * the movie is not paused, or if the movie's cursor is already at the end.
496  */
497 void MovieTexture::
498 restart() {
499  CDWriter cdata(_cycler);
500  if (!cdata->_playing) {
502  cdata->_clock = cdata->_clock - (now * cdata->_play_rate);
503  cdata->_playing = true;
504  }
505 }
506 
507 /**
508  * Stops a currently playing or looping movie right where it is. The movie's
509  * cursor remains frozen at the point where it was stopped.
510  */
511 void MovieTexture::
512 stop() {
513  CDWriter cdata(_cycler);
514  if (cdata->_playing) {
516  cdata->_clock = cdata->_clock + (now * cdata->_play_rate);
517  cdata->_playing = false;
518  }
519 }
520 
521 /**
522  * Plays the movie from the beginning.
523  */
524 void MovieTexture::
525 play() {
526  CDWriter cdata(_cycler);
528  cdata->_clock = 0.0 - (now * cdata->_play_rate);
529  cdata->_playing = true;
530 }
531 
532 /**
533  * Sets the movie's cursor.
534  */
535 void MovieTexture::
536 set_time(double t) {
537  CDWriter cdata(_cycler);
538  t = std::min(cdata->_video_length, std::max(0.0, t));
539  if (cdata->_playing) {
541  cdata->_clock = t - (now * cdata->_play_rate);
542  } else {
543  cdata->_clock = t;
544  }
545 }
546 
547 /**
548  * Returns the current value of the movie's cursor. If the movie's loop count
549  * is greater than one, then its length is effectively multiplied for the
550  * purposes of this function. In other words, the return value will be in the
551  * range 0.0 to (length * loopcount).
552  */
553 double MovieTexture::
554 get_time() const {
555  CDReader cdata(_cycler);
556  double clock = cdata->_clock;
557  if (cdata->_playing) {
559  clock += (now * cdata->_play_rate);
560  }
561  return clock;
562 }
563 
564 /**
565  * If true, sets the movie's loop count to 1 billion. If false, sets the
566  * movie's loop count to one.
567  */
568 void MovieTexture::
569 set_loop(bool loop) {
570  set_loop_count(loop ? 0:1);
571 }
572 
573 /**
574  * Returns true if the movie's loop count is not equal to one.
575  */
576 bool MovieTexture::
577 get_loop() const {
578  CDReader cdata(_cycler);
579  return (cdata->_loop_count == 0);
580 }
581 
582 /**
583  * Sets the movie's loop count to the desired value.
584  */
585 void MovieTexture::
586 set_loop_count(int n) {
587  CDWriter cdata(_cycler);
588  cdata->_loop_count = n;
589 }
590 
591 /**
592  * Returns the movie's loop count.
593  */
594 int MovieTexture::
595 get_loop_count() const {
596  CDReader cdata(_cycler);
597  return cdata->_loop_count;
598 }
599 
600 /**
601  * Sets the movie's play-rate. This is the speed at which the movie's cursor
602  * advances. The default is to advance 1.0 movie-seconds per real-time
603  * second.
604  */
605 void MovieTexture::
606 set_play_rate(double rate) {
607  CDWriter cdata(_cycler);
608  if (cdata->_playing) {
610  cdata->_clock += (now * cdata->_play_rate);
611  cdata->_play_rate = rate;
612  cdata->_clock -= (now * cdata->_play_rate);
613  } else {
614  cdata->_play_rate = rate;
615  }
616 }
617 
618 /**
619  * Gets the movie's play-rate.
620  */
621 double MovieTexture::
622 get_play_rate() const {
623  CDReader cdata(_cycler);
624  return cdata->_play_rate;
625 }
626 
627 /**
628  * Returns true if the movie's cursor is advancing.
629  */
630 bool MovieTexture::
631 is_playing() const {
632  CDReader cdata(_cycler);
633  return cdata->_playing;
634 }
635 
636 /**
637  * Synchronize this texture to a sound. Typically, you would load the texture
638  * and the sound from the same AVI file.
639  */
640 void MovieTexture::
641 synchronize_to(AudioSound *s) {
642  CDWriter cdata(_cycler);
643  cdata->_synchronize = s;
644 }
645 
646 /**
647  * Stop synchronizing with a sound.
648  */
649 void MovieTexture::
650 unsynchronize() {
651  CDWriter cdata(_cycler);
652  cdata->_synchronize = nullptr;
653 }
654 
655 
656 /**
657  * Called internally to sync all of the frames to the current time. Returns
658  * true if successful, or false of some of the frames are out-of-date with
659  * each other.
660  */
661 bool MovieTexture::
662 do_update_frames(const CData *cdata) const {
663  // Throughout this method, we cast the VideoPage to non-const to update the
664  // _cbuffer or _abuffer member. We can do this safely because this is only
665  // a transparent cache value.
666  nassertr(cdata->_has_offset, false);
667 
668  // First, go through and get all of the current frames.
669  Pages::const_iterator pi;
670  for (pi = cdata->_pages.begin(); pi != cdata->_pages.end(); ++pi) {
671  const VideoPage &page = (*pi);
672  MovieVideoCursor *color = page._color;
673  MovieVideoCursor *alpha = page._alpha;
674 
675  if (color != nullptr && page._cbuffer == nullptr) {
676  if (color->set_time(cdata->_offset, cdata->_true_loop_count)) {
677  ((VideoPage &)page)._cbuffer = color->fetch_buffer();
678  }
679  }
680  if (alpha != nullptr && page._abuffer == nullptr) {
681  if (alpha->set_time(cdata->_offset, cdata->_true_loop_count)) {
682  ((VideoPage &)page)._abuffer = alpha->fetch_buffer();
683  }
684  }
685  }
686 
687  if (!movies_sync_pages) {
688  // If movies-sync-pages is configured off, we don't care about syncing the
689  // pages, and we always return true here to render the pages we've got.
690  return true;
691  }
692 
693  // Now make sure all of the frames are in sync with each other.
694  bool in_sync = true;
695  bool any_frames = false;
696  bool any_dropped = false;
697  PT(MovieVideoCursor::Buffer) newest;
698  for (pi = cdata->_pages.begin(); pi != cdata->_pages.end(); ++pi) {
699  const VideoPage &page = (*pi);
700  if (page._cbuffer == nullptr) {
701  if (page._color != nullptr) {
702  // This page isn't ready at all.
703  in_sync = false;
704  }
705  } else {
706  nassertr(page._color != nullptr, true);
707  any_frames = true;
708  if (newest == nullptr) {
709  newest = page._cbuffer;
710  } else {
711  int ref = newest->compare_timestamp(page._cbuffer);
712  if (ref != 0) {
713  // This page is ready, but out-of-date.
714  in_sync = false;
715  any_dropped = true;
716  if (ref < 0) {
717  newest = page._cbuffer;
718  }
719  }
720  }
721  }
722  if (page._abuffer == nullptr) {
723  if (page._alpha != nullptr) {
724  in_sync = false;
725  }
726  } else {
727  nassertr(page._alpha != nullptr, true);
728  any_frames = true;
729  if (newest == nullptr) {
730  newest = page._abuffer;
731  } else {
732  int ref = newest->compare_timestamp(page._abuffer);
733  if (ref != 0) {
734  in_sync = false;
735  any_dropped = true;
736  if (ref < 0) {
737  newest = page._abuffer;
738  }
739  }
740  }
741  }
742  }
743 
744  if (!any_frames) {
745  // If no frames at all are ready yet, just carry on.
746  return true;
747  }
748 
749  if (!in_sync) {
750  // If we're not in sync, throw away pages that are older than the newest
751  // available frame.
752  if (newest != nullptr) {
753  Pages::const_iterator pi;
754  for (pi = cdata->_pages.begin(); pi != cdata->_pages.end(); ++pi) {
755  const VideoPage &page = (*pi);
756  if (page._cbuffer != nullptr && newest->compare_timestamp(page._cbuffer) > 0) {
757  ((VideoPage &)page)._cbuffer.clear();
758  any_dropped = true;
759  }
760  if (page._abuffer != nullptr && newest->compare_timestamp(page._abuffer) > 0) {
761  ((VideoPage &)page)._abuffer.clear();
762  any_dropped = true;
763  }
764  }
765 
766  if (any_dropped) {
767  // If we dropped one or more frames for being out-of-sync, implying
768  // that compare_timestamp() is implemented, then we also want to
769  // update our internal offset value so that future frames will get the
770  // same value.
771  ((CData *)cdata)->_offset = newest->get_timestamp();
772  }
773  }
774  }
775 
776  return in_sync;
777 }
778 
779 /**
780  * Factory method to generate a Texture object
781  */
782 void MovieTexture::
783 register_with_read_factory() {
784  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
785 }
786 
787 /**
788  * Factory method to generate a MovieTexture object
789  */
790 TypedWritable *MovieTexture::
791 make_from_bam(const FactoryParams &params) {
792  PT(MovieTexture) dummy = new MovieTexture("");
793  return dummy->make_this_from_bam(params);
794 }
795 
796 /**
797  * Receives an array of pointers, one for each time manager->read_pointer()
798  * was called in fillin(). Returns the number of pointers processed.
799  */
800 int MovieTexture::
801 complete_pointers(TypedWritable **p_list, BamReader *manager) {
802  int pi = Texture::complete_pointers(p_list, manager);
803 
804  CDWriter cdata(_cycler);
805  size_t num_pages = cdata->_pages.size();
806  for (size_t n = 0; n < num_pages; ++n) {
807  VideoPage &page = cdata->_pages[n];
808  page._color = DCAST(MovieVideoCursor, p_list[pi++]);
809  page._alpha = DCAST(MovieVideoCursor, p_list[pi++]);
810  }
811 
812  return pi;
813 }
814 
815 /**
816  * Writes the rawdata part of the texture to the Datagram.
817  */
818 void MovieTexture::
819 do_write_datagram_rawdata(Texture::CData *cdata_tex, BamWriter *manager, Datagram &dg) {
820  CDReader cdata(_cycler);
821 
822  dg.add_uint16(cdata_tex->_z_size);
823  if (manager->get_file_minor_ver() >= 26) {
824  dg.add_uint16(cdata_tex->_num_views);
825  }
826 
827  nassertv(cdata->_pages.size() == (size_t)(cdata_tex->_z_size * cdata_tex->_num_views));
828  for (size_t n = 0; n < cdata->_pages.size(); ++n) {
829  const VideoPage &page = cdata->_pages[n];
830  manager->write_pointer(dg, page._color);
831  manager->write_pointer(dg, page._alpha);
832  }
833 }
834 
835 /**
836  * Reads in the part of the Texture that was written with
837  * do_write_datagram_rawdata().
838  */
839 void MovieTexture::
840 do_fillin_rawdata(Texture::CData *cdata_tex, DatagramIterator &scan, BamReader *manager) {
841  CDWriter cdata(_cycler);
842 
843  cdata_tex->_z_size = scan.get_uint16();
844  cdata_tex->_num_views = 1;
845  if (manager->get_file_minor_ver() >= 26) {
846  cdata_tex->_num_views = scan.get_uint16();
847  }
848 
849  size_t num_pages = (size_t)(cdata_tex->_z_size * cdata_tex->_num_views);
850  cdata->_pages.reserve(num_pages);
851  for (size_t n = 0; n < num_pages; ++n) {
852  cdata->_pages.push_back(VideoPage());
853  manager->read_pointer(scan); // page._color
854  manager->read_pointer(scan); // page._alpha
855  }
856 
857  // We load one or more MovieVideoCursors during the above loop. We need a
858  // finalize callback so we can initialize ourselves once those cursors have
859  // been read completely.
860  manager->register_finalize(this);
861 }
862 
863 /**
864  * Called by the BamReader to perform any final actions needed for setting up
865  * the object after all objects have been read and all pointers have been
866  * completed.
867  */
868 void MovieTexture::
869 finalize(BamReader *manager) {
870  Texture::CDWriter cdata_tex(Texture::_cycler);
871  CDWriter cdata(_cycler);
872 
873  // Insist that each of our video pages gets finalized before we do.
874  size_t num_pages = cdata->_pages.size();
875  for (size_t n = 0; n < num_pages; ++n) {
876  VideoPage &page = cdata->_pages[n];
877  manager->finalize_now(page._color);
878  manager->finalize_now(page._alpha);
879  }
880 
881  do_recalculate_image_properties(cdata, cdata_tex, LoaderOptions());
882 
883  set_loaded_from_image();
884  set_loop(true);
885  play();
886 }
887 
888 #endif // HAVE_AUDIO
CycleData
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:47
BamCacheRecord
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
Definition: bamCacheRecord.h:35
DatagramIterator::get_uint16
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
Definition: datagramIterator.I:145
MovieVideoCursor
A MovieVideo is actually any source that provides a sequence of video frames.
Definition: movieVideoCursor.h:41
movieVideoCursor.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pvector
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
config_gobj.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pandabase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
TypedWritable::complete_pointers
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: typedWritable.cxx:81
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
clockObject.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Filename::get_basename_wo_extension
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:386
bamCacheRecord.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ClockObject::get_global_clock
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
BamWriter::write_pointer
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
MovieVideoCursor::apply_to_texture_alpha
virtual void apply_to_texture_alpha(const Buffer *buffer, Texture *t, int page, int alpha_src)
Copies this buffer's contents into the alpha channel of the supplied texture.
Definition: movieVideoCursor.cxx:182
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
Texture
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:71
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LoaderOptions
Specifies parameters that may be passed to the loader.
Definition: loaderOptions.h:23
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
PNMImage
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Definition: pnmImage.h:58
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
movieTexture.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PfmFile
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component,...
Definition: pfmFile.h:31
BamWriter::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being written.
Definition: bamWriter.I:59
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Datagram::add_uint16
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
BamReader::register_finalize
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
Definition: bamReader.cxx:808
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
CycleDataWriter
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
Definition: cycleDataWriter.h:34
MovieTypeRegistry
This class records the different types of MovieAudio and MovieVideo that are available for loading.
Definition: movieTypeRegistry.h:28
CycleDataReader
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
Definition: cycleDataReader.h:35
CullTraverserData
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Definition: cullTraverserData.h:40
movieTypeRegistry.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
MovieVideo
A MovieVideo is actually any source that provides a sequence of video frames.
Definition: movieVideo.h:38
Factory::register_factory
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
MovieVideoCursor::apply_to_texture_rgb
virtual void apply_to_texture_rgb(const Buffer *buffer, Texture *t, int page)
Copies this buffer's contents into the RGB channels of the supplied texture.
Definition: movieVideoCursor.cxx:249
ClockObject::get_frame_time
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition: clockObject.h:91
config_grutil.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamReader::finalize_now
void finalize_now(TypedWritable *whom)
Forces the finalization of a particular object.
Definition: bamReader.cxx:897
BamReader::read_pointer
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
AudioSound
Definition: audioSound.h:25
MovieTypeRegistry::get_global_ptr
static MovieTypeRegistry * get_global_ptr()
Returns a pointer to the global MovieTypeRegistry instance.
Definition: movieTypeRegistry.I:18
BamReader::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
MovieVideoCursor::Buffer
Definition: movieVideoCursor.h:62
MovieVideoCursor::set_time
virtual bool set_time(double timestamp, int loop_count)
Updates the cursor to the indicated time.
Definition: movieVideoCursor.cxx:100
BamCacheRecord::add_dependent_file
void add_dependent_file(const Filename &pathname)
Adds the indicated file to the list of files that will be loaded to generate the data in this record.
Definition: bamCacheRecord.cxx:147
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
audioSound.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
MovieVideoCursor::apply_to_texture
virtual void apply_to_texture(const Buffer *buffer, Texture *t, int page)
Stores this buffer's contents in the indicated texture.
Definition: movieVideoCursor.cxx:121
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
movieVideo.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.