Panda3D
movieVideoCursor.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 movieVideoCursor.cxx
10  * @author jyelon
11  * @date 2007-07-02
12  */
13 
14 #include "movieVideoCursor.h"
15 #include "config_movies.h"
16 #include "pStatCollector.h"
17 #include "pStatTimer.h"
18 #include "bamReader.h"
19 #include "bamWriter.h"
20 
21 PStatCollector MovieVideoCursor::_copy_pcollector("*:Copy Video into Texture");
22 PStatCollector MovieVideoCursor::_copy_pcollector_ram("*:Copy Video into Texture:modify_ram_image");
23 PStatCollector MovieVideoCursor::_copy_pcollector_copy("*:Copy Video into Texture:copy");
24 
25 TypeHandle MovieVideoCursor::_type_handle;
26 TypeHandle MovieVideoCursor::Buffer::_type_handle;
27 
28 /**
29  * This is a virtual base class and should not be created directly. Instead,
30  * create a more specialized class.
31  */
32 MovieVideoCursor::
33 MovieVideoCursor(MovieVideo *src) :
34  _source(src),
35  _size_x(1),
36  _size_y(1),
37  _num_components(3),
38  _length(1.0E10),
39  _can_seek(true),
40  _can_seek_fast(true),
41  _aborted(false),
42  _streaming(false),
43  _ready(false)
44 {
45 }
46 
47 /**
48  *
49  */
50 MovieVideoCursor::
51 ~MovieVideoCursor() {
52 }
53 
54 /**
55  * Set up the specified Texture object to contain content from this movie.
56  * This should be called once, not every frame.
57  */
59 setup_texture(Texture *tex) const {
60  int fullx = size_x();
61  int fully = size_y();
62  tex->adjust_this_size(fullx, fully, tex->get_name(), true);
63  Texture::Format fmt;
64  switch (get_num_components()) {
65  case 1:
66  fmt = Texture::F_luminance;
67  break;
68  case 2:
69  fmt = Texture::F_luminance_alpha;
70  break;
71  default:
72  fmt = Texture::F_rgb;
73  break;
74  case 4:
75  fmt = Texture::F_rgba;
76  break;
77  }
78  tex->setup_texture(Texture::TT_2d_texture, fullx, fully, 1, Texture::T_unsigned_byte, fmt);
79  tex->set_pad_size(fullx - size_x(), fully - size_y());
80 }
81 
82 /**
83  * Updates the cursor to the indicated time. If loop_count >= 1, the time is
84  * clamped to the movie's length * loop_count. If loop_count <= 0, the time
85  * is understood to be modulo the movie's length.
86  *
87  * Returns true if a new frame is now available, false otherwise. If this
88  * returns true, you should immediately follow this with exactly *one* call to
89  * fetch_buffer().
90  *
91  * If the movie reports that it can_seek, you may also specify a time value
92  * less than the previous value you passed to set_time(). Otherwise, you may
93  * only specify a time value greater than or equal to the previous value.
94  *
95  * If the movie reports that it can_seek, it doesn't mean that it can do so
96  * quickly. It may have to rewind the movie and then fast forward to the
97  * desired location. Only if can_seek_fast returns true can it seek rapidly.
98  */
100 set_time(double timestamp, int loop_count) {
101  return true;
102 }
103 
104 /**
105  * Gets the current video frame (as specified by set_time()) from the movie
106  * and returns it in a pre-allocated buffer. You may simply let the buffer
107  * dereference and delete itself when you are done with it.
108  *
109  * This may return NULL (even if set_time() returned true) if the frame is not
110  * available for some reason.
111  */
112 PT(MovieVideoCursor::Buffer) MovieVideoCursor::
113 fetch_buffer() {
114  return nullptr;
115 }
116 
117 /**
118  * Stores this buffer's contents in the indicated texture.
119  */
121 apply_to_texture(const Buffer *buffer, Texture *t, int page) {
122  if (buffer == nullptr) {
123  return;
124  }
125 
126  PStatTimer timer(_copy_pcollector);
127 
128  nassertv(t->get_x_size() >= size_x());
129  nassertv(t->get_y_size() >= size_y());
130  nassertv((t->get_num_components() == 3) || (t->get_num_components() == 4) ||
131  (t->get_num_components() == 1 && get_num_components() == 1) ||
132  (t->get_num_components() == 2 && get_num_components() == 2));
133  nassertv(t->get_component_width() == 1);
134  nassertv(page < t->get_num_pages());
135 
136  PTA_uchar img;
137  {
138  PStatTimer timer2(_copy_pcollector_ram);
139  t->set_keep_ram_image(true);
140  img = t->modify_ram_image();
141  }
142 
143  unsigned char *data = img.p() + page * t->get_expected_ram_page_size();
144 
145  PStatTimer timer2(_copy_pcollector_copy);
146  if (t->get_x_size() == size_x() && t->get_num_components() == get_num_components()) {
147  memcpy(data, buffer->_block, size_x() * size_y() * get_num_components());
148 
149  } else {
150  unsigned char *p = buffer->_block;
151  int src_width = get_num_components();
152  int dst_width = t->get_num_components();
153  if (src_width == dst_width) {
154  int src_stride = src_width * size_x();
155  int dst_stride = dst_width * t->get_x_size();
156  for (int y=0; y<size_y(); y++) {
157  memcpy(data, p, src_stride);
158  data += dst_stride;
159  p += src_stride;
160  }
161  } else {
162  nassertv(src_width >= 3);
163  nassertv(dst_width >= 3);
164  for (int y = 0; y < size_y(); ++y) {
165  for (int x = 0; x < size_x(); ++x) {
166  data[0] = p[0];
167  data[1] = p[1];
168  data[2] = p[2];
169  data += dst_width;
170  p += src_width;
171  }
172  }
173  }
174  }
175 }
176 
177 /**
178  * Copies this buffer's contents into the alpha channel of the supplied
179  * texture. The RGB channels of the texture are not touched.
180  */
182 apply_to_texture_alpha(const Buffer *buffer, Texture *t, int page, int alpha_src) {
183  if (buffer == nullptr) {
184  return;
185  }
186 
187  PStatTimer timer(_copy_pcollector);
188 
189  // Is this a grayscale texture?
190  if (get_num_components() < 3) {
191  if (get_num_components() == 1 || alpha_src < 2 || alpha_src == 3) {
192  // There's only one "RGB" channel to take from.
193  alpha_src = 1;
194  } else {
195  // Alpha is actually in the second channel for grayscale-alpha.
196  alpha_src = 2;
197  }
198  }
199 
200  nassertv(t->get_x_size() >= size_x());
201  nassertv(t->get_y_size() >= size_y());
202  nassertv(t->get_num_components() == 4 || t->get_num_components() == 2);
203  nassertv(t->get_component_width() == 1);
204  nassertv(page < t->get_z_size());
205  nassertv((alpha_src >= 0) && (alpha_src <= get_num_components()));
206 
207  PTA_uchar img;
208  {
209  PStatTimer timer2(_copy_pcollector_ram);
210  t->set_keep_ram_image(true);
211  img = t->modify_ram_image();
212  }
213 
214  unsigned char *data = img.p() + page * t->get_expected_ram_page_size();
215 
216  PStatTimer timer2(_copy_pcollector_copy);
217  int src_width = get_num_components();
218  int dst_width = t->get_num_components();
219  int src_stride = size_x() * src_width;
220  int dst_stride = t->get_x_size() * dst_width;
221  unsigned char *p = buffer->_block;
222  if (alpha_src == 0) {
223  nassertv(src_width >= 3);
224  for (int y=0; y<size_y(); y++) {
225  for (int x=0; x<size_x(); x++) {
226  unsigned char *pp = &p[x * src_width];
227  data[(x + 1) * dst_width - 1] = (pp[0] + pp[1] + pp[2]) / 3;
228  }
229  data += dst_stride;
230  p += src_stride;
231  }
232  } else {
233  alpha_src -= 1;
234  for (int y=0; y<size_y(); y++) {
235  for (int x=0; x<size_x(); x++) {
236  data[(x + 1) * dst_width - 1] = p[x * src_width + alpha_src];
237  }
238  data += dst_stride;
239  p += src_stride;
240  }
241  }
242 }
243 
244 /**
245  * Copies this buffer's contents into the RGB channels of the supplied
246  * texture. The alpha channel of the texture is not touched.
247  */
249 apply_to_texture_rgb(const Buffer *buffer, Texture *t, int page) {
250  if (buffer == nullptr) {
251  return;
252  }
253 
254  PStatTimer timer(_copy_pcollector);
255 
256  nassertv(t->get_x_size() >= size_x());
257  nassertv(t->get_y_size() >= size_y());
258  nassertv(t->get_num_components() == 4 || t->get_num_components() == 2);
259  nassertv(t->get_component_width() == 1);
260  nassertv(page < t->get_z_size());
261 
262  PTA_uchar img;
263  {
264  PStatTimer timer2(_copy_pcollector_ram);
265  t->set_keep_ram_image(true);
266  img = t->modify_ram_image();
267  }
268 
269  unsigned char *data = img.p() + page * t->get_expected_ram_page_size();
270 
271  PStatTimer timer2(_copy_pcollector_copy);
272  int src_width = get_num_components();
273  int dst_width = t->get_num_components();
274  int src_stride = size_x() * src_width;
275  int dst_stride = t->get_x_size() * dst_width;
276  unsigned char *p = buffer->_block;
277  if (src_width >= 3) {
278  // It has RGB values.
279  nassertv(dst_width >= 3);
280  for (int y = 0; y < size_y(); ++y) {
281  for (int x = 0; x < size_x(); ++x) {
282  data[x * dst_width + 0] = p[x * src_width + 0];
283  data[x * dst_width + 1] = p[x * src_width + 1];
284  data[x * dst_width + 2] = p[x * src_width + 2];
285  }
286  data += dst_stride;
287  p += src_stride;
288  }
289  } else if (dst_width == 4) {
290  // It has only grayscale.
291  for (int y = 0; y < size_y(); ++y) {
292  for (int x = 0; x < size_x(); ++x) {
293  unsigned char gray = p[x * src_width];
294  data[x * dst_width + 0] = gray;
295  data[x * dst_width + 1] = gray;
296  data[x * dst_width + 2] = gray;
297  }
298  data += dst_stride;
299  p += src_stride;
300  }
301  }
302 }
303 
304 /**
305  * May be called by a derived class to return a single standard Buffer object
306  * to easily implement fetch_buffer().
307  */
308 MovieVideoCursor::Buffer *MovieVideoCursor::
309 get_standard_buffer() {
310  if (_standard_buffer == nullptr) {
311  _standard_buffer = make_new_buffer();
312  }
313  return _standard_buffer;
314 }
315 
316 /**
317  * May be called by a derived class to allocate a new Buffer object.
318  */
319 PT(MovieVideoCursor::Buffer) MovieVideoCursor::
320 make_new_buffer() {
321  return new Buffer(size_x() * size_y() * get_num_components());
322 }
323 
324 /**
325  * Writes the contents of this object to the datagram for shipping out to a
326  * Bam file.
327  */
331 
332  manager->write_pointer(dg, _source);
333 }
334 
335 /**
336  * Receives an array of pointers, one for each time manager->read_pointer()
337  * was called in fillin(). Returns the number of pointers processed.
338  */
341  int pi = TypedWritableReferenceCount::complete_pointers(p_list, manager);
342 
343  _source = DCAST(MovieVideo, p_list[pi++]);
344 
345  return pi;
346 }
347 
348 /**
349  * This internal function is called by make_from_bam to read in all of the
350  * relevant data from the BamFile for the new MovieVideoCursor.
351  */
352 void MovieVideoCursor::
353 fillin(DatagramIterator &scan, BamReader *manager) {
355 
356  manager->read_pointer(scan); // _source
357 }
358 
359 /**
360  *
361  */
362 MovieVideoCursor::Buffer::
363 Buffer(size_t block_size) :
364  _block_size(block_size)
365 {
366  _deleted_chain = memory_hook->get_deleted_chain(_block_size);
367  _block = (unsigned char *)_deleted_chain->allocate(_block_size, get_class_type());
368 }
369 
370 /**
371  *
372  */
373 MovieVideoCursor::Buffer::
374 ~Buffer() {
375  _deleted_chain->deallocate(_block, get_class_type());
376 }
377 
378 /**
379  * Used to sort different buffers to ensure they correspond to the same source
380  * frame, particularly important when synchronizing the different pages of a
381  * multi-page texture.
382  *
383  * Returns 0 if the two buffers are of the same frame, <0 if this one comes
384  * earlier than the other one, and >0 if the other one comes earlier.
385  */
387 compare_timestamp(const Buffer *other) const {
388  return 0;
389 }
390 
391 /**
392  * Returns the nearest timestamp value of this particular buffer. Ideally,
393  * MovieVideoCursor::set_time() for this timestamp would return this buffer
394  * again. This need be defined only if compare_timestamp() is also defined.
395  */
397 get_timestamp() const {
398  return 0.0;
399 }
get_y_size
Returns the height of the texture image in texels.
Definition: texture.h:338
DeletedBufferChain * get_deleted_chain(size_t buffer_size)
Returns a pointer to a global DeletedBufferChain object suitable for allocating arrays of the indicat...
Definition: memoryHook.cxx:598
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
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
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
void setup_texture(TextureType texture_type, int x_size, int y_size, int z_size, ComponentType component_type, Format format)
Sets the texture to the indicated type and dimensions, presumably in preparation for calling read() o...
Definition: texture.I:52
void setup_texture(Texture *tex) const
Set up the specified Texture object to contain content from this movie.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
void * allocate(size_t size, TypeHandle type_handle)
Allocates the memory for a new buffer of the indicated size (which must be no greater than the fixed ...
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.
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
bool adjust_this_size(int &x_size, int &y_size, const std::string &name, bool for_padding) const
Works like adjust_size, but also considers the texture class.
Definition: texture.I:2154
Definition: buffer.h:24
A lightweight class that represents a single element that may be timed and/or counted via stats.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
virtual bool set_time(double timestamp, int loop_count)
Updates the cursor to the indicated time.
get_expected_ram_page_size
Returns the number of bytes that should be used per each Z page of the 3-d texture.
Definition: texture.h:441
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().
set_keep_ram_image
Sets the flag that indicates whether this Texture is eligible to have its main RAM copy of the textur...
Definition: texture.h:464
void set_pad_size(int x=0, int y=0, int z=0)
Sets the size of the pad region.
Definition: texture.I:677
void deallocate(void *ptr, TypeHandle type_handle)
Frees the memory for a buffer previously allocated via allocate().
get_num_components
Returns the number of color components for each texel of the texture image.
Definition: texture.h:355
virtual int compare_timestamp(const Buffer *other) const
Used to sort different buffers to ensure they correspond to the same source frame,...
virtual void apply_to_texture(const Buffer *buffer, Texture *t, int page)
Stores this buffer's contents in the indicated texture.
get_component_width
Returns the number of bytes stored for each color component of a texel.
Definition: texture.h:356
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT(MovieVideoCursor::Buffer) MovieVideoCursor
Gets the current video frame (as specified by set_time()) from the movie and returns it in a pre-allo...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
A MovieVideo is actually any source that provides a sequence of video frames.
Definition: movieVideo.h:38
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.
A class to retrieve the individual data elements previously stored in a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PTA_uchar modify_ram_image()
Returns a modifiable pointer to the system-RAM image.
Definition: texture.I:1382
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
get_x_size
Returns the width of the texture image in texels.
Definition: texture.h:334
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
virtual double get_timestamp() const
Returns the nearest timestamp value of this particular buffer.