Panda3D
|
00001 // Filename: movieVideo.cxx 00002 // Created by: jyelon (02Jul07) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "movieVideoCursor.h" 00016 #include "config_movies.h" 00017 #include "pStatCollector.h" 00018 #include "pStatTimer.h" 00019 00020 TypeHandle MovieVideoCursor::_type_handle; 00021 00022 //////////////////////////////////////////////////////////////////// 00023 // Function: MovieVideoCursor::Constructor 00024 // Access: Public 00025 // Description: This constructor returns a null video stream --- a 00026 // stream of plain blue and white frames that last one 00027 // second each. To get more interesting video, you need 00028 // to construct a subclass of this class. 00029 //////////////////////////////////////////////////////////////////// 00030 MovieVideoCursor:: 00031 MovieVideoCursor(MovieVideo *src) : 00032 _conversion_buffer(0), 00033 _source(src), 00034 _size_x(1), 00035 _size_y(1), 00036 _num_components(3), 00037 _length(1.0E10), 00038 _can_seek(true), 00039 _can_seek_fast(true), 00040 _aborted(false), 00041 _last_start(-1.0), 00042 _next_start(0.0), 00043 _streaming(false), 00044 _ready(false) 00045 { 00046 } 00047 00048 //////////////////////////////////////////////////////////////////// 00049 // Function: MovieVideoCursor::Destructor 00050 // Access: Public, Virtual 00051 // Description: 00052 //////////////////////////////////////////////////////////////////// 00053 MovieVideoCursor:: 00054 ~MovieVideoCursor() { 00055 if (_conversion_buffer != 0) { 00056 delete[] _conversion_buffer; 00057 } 00058 } 00059 00060 //////////////////////////////////////////////////////////////////// 00061 // Function: MovieVideoCursor::allocate_conversion_buffer 00062 // Access: Private 00063 // Description: The generic implementations of fetch_into_texture 00064 // and fetch_into_alpha require the use of a conversion 00065 // buffer. This allocates the buffer. 00066 //////////////////////////////////////////////////////////////////// 00067 void MovieVideoCursor:: 00068 allocate_conversion_buffer() { 00069 if (_conversion_buffer == 0) { 00070 _conversion_buffer = new unsigned char[size_x() * size_y() * 4]; 00071 } 00072 } 00073 00074 //////////////////////////////////////////////////////////////////// 00075 // Function: MovieVideoCursor::setup_texture 00076 // Access: Published 00077 // Description: Set up the specified Texture object to contain 00078 // content from this movie. This should be called 00079 // once, not every frame. 00080 //////////////////////////////////////////////////////////////////// 00081 void MovieVideoCursor:: 00082 setup_texture(Texture *tex) const { 00083 int fullx = size_x(); 00084 int fully = size_y(); 00085 if (Texture::get_textures_power_2()) { 00086 fullx = Texture::up_to_power_2(fullx); 00087 fully = Texture::up_to_power_2(fully); 00088 } 00089 Texture::Format fmt = (get_num_components() == 4) ? Texture::F_rgba : Texture::F_rgb; 00090 tex->setup_texture(Texture::TT_2d_texture, fullx, fully, 1, Texture::T_unsigned_byte, fmt); 00091 tex->set_pad_size(fullx - size_x(), fully - size_y()); 00092 } 00093 00094 //////////////////////////////////////////////////////////////////// 00095 // Function: MovieVideoCursor::fetch_into_bitbucket 00096 // Access: Published, Virtual 00097 // Description: Discards the next video frame. Still sets 00098 // last_start and next_start. 00099 // 00100 // See fetch_into_buffer for more details. 00101 //////////////////////////////////////////////////////////////////// 00102 void MovieVideoCursor:: 00103 fetch_into_bitbucket(double time) { 00104 00105 // This generic implementation is layered on fetch_into_buffer. 00106 // It will work for any derived class, so it is never necessary to 00107 // redefine this. It is probably possible to make a faster 00108 // implementation, but since this function is rarely used, it 00109 // probably isn't worth the trouble. 00110 00111 allocate_conversion_buffer(); 00112 fetch_into_buffer(time, _conversion_buffer, false); 00113 } 00114 00115 //////////////////////////////////////////////////////////////////// 00116 // Function: MovieVideoCursor::fetch_into_texture 00117 // Access: Published, Virtual 00118 // Description: Reads the specified video frame into 00119 // the specified texture. 00120 // 00121 // See fetch_into_buffer for more details. 00122 //////////////////////////////////////////////////////////////////// 00123 static PStatCollector fetch_into_texture_collector("*:Decode Video into Texture"); 00124 void MovieVideoCursor:: 00125 fetch_into_texture(double time, Texture *t, int page) { 00126 PStatTimer timer(fetch_into_texture_collector); 00127 00128 // This generic implementation is layered on fetch_into_buffer. 00129 // It will work for any derived class, so it is never necessary to 00130 // redefine this. However, it may be possible to make a faster 00131 // implementation that uses fewer intermediate copies, depending 00132 // on the capabilities of the underlying codec software. 00133 00134 nassertv(t->get_x_size() >= size_x()); 00135 nassertv(t->get_y_size() >= size_y()); 00136 nassertv((t->get_num_components() == 3) || (t->get_num_components() == 4)); 00137 nassertv(t->get_component_width() == 1); 00138 nassertv(page < t->get_z_size()); 00139 00140 PTA_uchar img = t->modify_ram_image(); 00141 00142 unsigned char *data = img.p() + page * t->get_expected_ram_page_size(); 00143 00144 if (t->get_x_size() == size_x()) { 00145 fetch_into_buffer(time, data, t->get_num_components() == 4); 00146 } else { 00147 allocate_conversion_buffer(); 00148 fetch_into_buffer(time, _conversion_buffer, t->get_num_components() == 4); 00149 int src_stride = size_x() * t->get_num_components(); 00150 int dst_stride = t->get_x_size() * t->get_num_components(); 00151 unsigned char *p = _conversion_buffer; 00152 for (int y=0; y<size_y(); y++) { 00153 memcpy(data, p, src_stride); 00154 data += dst_stride; 00155 p += src_stride; 00156 } 00157 } 00158 } 00159 00160 //////////////////////////////////////////////////////////////////// 00161 // Function: MovieVideoCursor::fetch_into_texture_alpha 00162 // Access: Published, Virtual 00163 // Description: Reads the specified video frame into 00164 // the alpha channel of the supplied texture. The 00165 // RGB channels of the texture are not touched. 00166 // 00167 // See fetch_into_buffer for more details. 00168 //////////////////////////////////////////////////////////////////// 00169 void MovieVideoCursor:: 00170 fetch_into_texture_alpha(double time, Texture *t, int page, int alpha_src) { 00171 00172 // This generic implementation is layered on fetch_into_buffer. 00173 // It will work for any derived class, so it is never necessary to 00174 // redefine this. However, it may be possible to make a faster 00175 // implementation that uses fewer intermediate copies, depending 00176 // on the capabilities of the underlying codec software. 00177 00178 nassertv(t->get_x_size() >= size_x()); 00179 nassertv(t->get_y_size() >= size_y()); 00180 nassertv(t->get_num_components() == 4); 00181 nassertv(t->get_component_width() == 1); 00182 nassertv(page < t->get_z_size()); 00183 nassertv((alpha_src >= 0) && (alpha_src <= 4)); 00184 00185 allocate_conversion_buffer(); 00186 00187 fetch_into_buffer(time, _conversion_buffer, true); 00188 00189 PTA_uchar img = t->modify_ram_image(); 00190 00191 unsigned char *data = img.p() + page * t->get_expected_ram_page_size(); 00192 00193 int src_stride = size_x() * 4; 00194 int dst_stride = t->get_x_size() * 4; 00195 if (alpha_src == 0) { 00196 unsigned char *p = _conversion_buffer; 00197 for (int y=0; y<size_y(); y++) { 00198 for (int x=0; x<size_x(); x++) { 00199 data[x*4+3] = (p[x*4+0] + p[x*4+1] + p[x*4+2]) / 3; 00200 } 00201 data += dst_stride; 00202 p += src_stride; 00203 } 00204 } else { 00205 alpha_src -= 1; 00206 unsigned char *p = _conversion_buffer; 00207 for (int y=0; y<size_y(); y++) { 00208 for (int x=0; x<size_x(); x++) { 00209 data[x*4+3] = p[x*4+alpha_src]; 00210 } 00211 data += dst_stride; 00212 p += src_stride; 00213 } 00214 } 00215 } 00216 00217 //////////////////////////////////////////////////////////////////// 00218 // Function: MovieVideoCursor::fetch_into_texture_rgb 00219 // Access: Published, Virtual 00220 // Description: Reads the specified video frame into 00221 // the RGB channels of the supplied texture. The alpha 00222 // channel of the texture is not touched. 00223 // 00224 // See fetch_into_buffer for more details. 00225 //////////////////////////////////////////////////////////////////// 00226 void MovieVideoCursor:: 00227 fetch_into_texture_rgb(double time, Texture *t, int page) { 00228 00229 // This generic implementation is layered on fetch_into_buffer. 00230 // It will work for any derived class, so it is never necessary to 00231 // redefine this. However, it may be possible to make a faster 00232 // implementation that uses fewer intermediate copies, depending 00233 // on the capabilities of the underlying codec software. 00234 00235 nassertv(t->get_x_size() >= size_x()); 00236 nassertv(t->get_y_size() >= size_y()); 00237 nassertv(t->get_num_components() == 4); 00238 nassertv(t->get_component_width() == 1); 00239 nassertv(page < t->get_z_size()); 00240 00241 allocate_conversion_buffer(); 00242 00243 fetch_into_buffer(time, _conversion_buffer, true); 00244 00245 PTA_uchar img = t->modify_ram_image(); 00246 00247 unsigned char *data = img.p() + page * t->get_expected_ram_page_size(); 00248 00249 int src_stride = size_x() * 4; 00250 int dst_stride = t->get_x_size() * 4; 00251 unsigned char *p = _conversion_buffer; 00252 for (int y=0; y<size_y(); y++) { 00253 for (int x=0; x<size_x(); x++) { 00254 data[x*4+0] = p[x*4+0]; 00255 data[x*4+1] = p[x*4+1]; 00256 data[x*4+2] = p[x*4+2]; 00257 } 00258 data += dst_stride; 00259 p += src_stride; 00260 } 00261 } 00262 00263 //////////////////////////////////////////////////////////////////// 00264 // Function: MovieVideoCursor::fetch_into_buffer 00265 // Access: Published, Virtual 00266 // Description: Reads the specified video frame into the supplied 00267 // BGR or BGRA buffer. The frame's begin and end 00268 // times are stored in last_start and next_start. 00269 // 00270 // If the movie reports that it can_seek, you may 00271 // also specify a timestamp less than next_start. 00272 // Otherwise, you may only specify a timestamp 00273 // greater than or equal to next_start. 00274 // 00275 // If the movie reports that it can_seek, it doesn't 00276 // mean that it can do so quickly. It may have to 00277 // rewind the movie and then fast forward to the 00278 // desired location. Only if can_seek_fast returns 00279 // true can it seek rapidly. 00280 //////////////////////////////////////////////////////////////////// 00281 void MovieVideoCursor:: 00282 fetch_into_buffer(double time, unsigned char *data, bool bgra) { 00283 00284 // The following is the implementation of the null video stream, ie, 00285 // a stream of blinking red and blue frames. This method must be 00286 // overridden by the subclass. 00287 00288 _last_start = floor(time); 00289 _next_start = _last_start + 1; 00290 00291 if (((int)_last_start) & 1) { 00292 data[0] = 255; 00293 data[1] = 128; 00294 data[2] = 128; 00295 } else { 00296 data[0] = 128; 00297 data[1] = 128; 00298 data[2] = 255; 00299 } 00300 if (bgra) { 00301 data[3] = 255; 00302 } 00303 } 00304