Getting closer to functional

This commit is contained in:
Josh Yelon 2007-08-14 04:17:16 +00:00
parent 299a3b4ae1
commit b1d7446c27
10 changed files with 343 additions and 80 deletions

View File

@ -24,6 +24,7 @@
#include "config_gobj.h"
#include "config_grutil.h"
#include "bamCacheRecord.h"
#include "math.h"
TypeHandle MovieTexture::_type_handle;
@ -48,7 +49,9 @@ MovieTexture::
MovieTexture(PT(MovieVideo) video) :
Texture(video->get_name())
{
do_load_one(video, NULL, 0);
// It is necessary to copy the video, because
// the cull thread will be accessing it.
do_load_one(video->make_copy(), NULL, 0);
}
////////////////////////////////////////////////////////////////////
@ -57,7 +60,14 @@ MovieTexture(PT(MovieVideo) video) :
// Description: xxx
////////////////////////////////////////////////////////////////////
MovieTexture::CData::
CData()
CData() :
_video_width(1),
_video_height(1),
_video_length(1.0),
_playing(false),
_clock(0.0),
_play_rate(1.0),
_loop_count(1)
{
}
@ -70,7 +80,12 @@ MovieTexture::CData::
CData(const CData &copy) :
_pages(copy._pages),
_video_width(copy._video_width),
_video_height(copy._video_height)
_video_height(copy._video_height),
_video_length(copy._video_length),
_playing(false),
_clock(0.0),
_play_rate(1.0),
_loop_count(1.0)
{
}
@ -120,6 +135,7 @@ MovieTexture(const MovieTexture &copy) :
cdata->_pages[i]._alpha = color[i]->make_copy();
}
}
recalculate_image_properties(cdata);
}
}
@ -183,27 +199,31 @@ VideoPage() :
////////////////////////////////////////////////////////////////////
void MovieTexture::
recalculate_image_properties(CDWriter &cdata) {
int x_max = 0;
int y_max = 0;
int x_max = 1;
int y_max = 1;
bool alpha = false;
double len = 0.0;
for (int i=0; i<_z_size; i++) {
MovieVideo *t = cdata->_pages[i]._color;
if (t) {
if (t->size_x() > x_max) x_max = t->size_x();
if (t->size_y() > y_max) y_max = t->size_y();
if (t->length() > len) len = t->length();
if (t->get_num_components() == 4) alpha=true;
}
t = cdata->_pages[i]._alpha;
if (t) {
if (t->size_x() > x_max) x_max = t->size_x();
if (t->size_y() > y_max) y_max = t->size_y();
if (t->length() > len) len = t->length();
alpha = true;
}
}
cdata->_video_width = x_max;
cdata->_video_height = y_max;
cdata->_video_length = len;
if (get_texture_type() == TT_cube_map) {
// Texture must be square.
@ -269,9 +289,13 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
_primary_file_num_channels = primary_file_num_channels;
_alpha_file_channel = alpha_file_channel;
return do_load_one(color, alpha, z);
if (!do_load_one(color, alpha, z)) {
return false;
}
set_loaded_from_image();
set_loop(true);
play();
}
////////////////////////////////////////////////////////////////////
@ -287,7 +311,6 @@ do_load_one(PT(MovieVideo) color, PT(MovieVideo) alpha, int z) {
cdata->_pages.resize(z+1);
cdata->_pages[z]._color = color;
cdata->_pages[z]._alpha = alpha;
cdata->_pages[z]._base_clock = ClockObject::get_global_clock()->get_frame_time();
recalculate_image_properties(cdata);
}
@ -353,25 +376,36 @@ has_cull_callback() const {
bool MovieTexture::
cull_callback(CullTraverser *, const CullTraverserData &) const {
CDReader cdata(_cycler);
// Calculate the cursor position modulo the length of the movie.
double now = ClockObject::get_global_clock()->get_frame_time();
double clock = cdata->_clock;
if (cdata->_playing) {
clock += now * cdata->_play_rate;
}
double offset;
if (clock >= cdata->_video_length * cdata->_loop_count) {
offset = cdata->_video_length;
} else {
offset = fmod(clock, cdata->_video_length);
}
for (int i=0; i<((int)(cdata->_pages.size())); i++) {
double delta = now - cdata->_pages[i]._base_clock;
MovieVideo *color = cdata->_pages[i]._color;
MovieVideo *alpha = cdata->_pages[i]._alpha;
if (color) {
double offset = delta;
if ((offset < color->last_start()) || (offset >= color->next_start())) {
if (alpha) {
color->fetch_into_texture_rgb(offset, (MovieTexture*)this, i);
} else {
color->fetch_into_texture(offset, (MovieTexture*)this, i);
}
if (color && alpha) {
if ((offset >= color->next_start())||
((offset < color->last_start()) && (color->can_seek()))) {
color->fetch_into_texture_rgb(offset, (MovieTexture*)this, i);
}
}
if (alpha) {
double offset = delta;
if ((offset < alpha->last_start()) || (offset >= alpha->next_start())) {
alpha->fetch_into_texture_alpha(offset, (MovieTexture*)this, i, _alpha_file_channel);
if ((offset >= alpha->next_start())||
((offset < alpha->last_start()) && (alpha->can_seek()))) {
alpha->fetch_into_texture_alpha(offset, (MovieTexture*)this, i, _alpha_file_channel);
}
} else if (color) {
if ((offset >= color->next_start())||
((offset < color->last_start()) && (color->can_seek()))) {
color->fetch_into_texture(offset, (MovieTexture*)this, i);
}
}
}
@ -404,3 +438,186 @@ reload_ram_image() {
// Therefore, this is not needed.
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::restart
// Access: Published
// Description: Start playing the movie from where it was last
// paused. Has no effect if the movie is not paused,
// or if the movie's cursor is already at the end.
////////////////////////////////////////////////////////////////////
void MovieTexture::
restart() {
CDWriter cdata(_cycler);
if (!cdata->_playing) {
double now = ClockObject::get_global_clock()->get_frame_time();
cdata->_clock = cdata->_clock - (now * cdata->_play_rate);
cdata->_playing = true;
}
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::stop
// Access: Published
// Description: Stops a currently playing or looping movie right
// where it is. The movie's cursor remains frozen at
// the point where it was stopped.
////////////////////////////////////////////////////////////////////
void MovieTexture::
stop() {
CDWriter cdata(_cycler);
if (cdata->_playing) {
double now = ClockObject::get_global_clock()->get_frame_time();
cdata->_clock = cdata->_clock + (now * cdata->_play_rate);
cdata->_playing = false;
}
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::play
// Access: Published
// Description: Plays the movie from the beginning.
////////////////////////////////////////////////////////////////////
void MovieTexture::
play() {
CDWriter cdata(_cycler);
double now = ClockObject::get_global_clock()->get_frame_time();
cdata->_clock = 0.0 - (now * cdata->_play_rate);
cdata->_playing = true;
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::set_time
// Access: Published
// Description: Sets the movie's cursor. If the movie's loop count
// count is greater than one, then its length is
// effectively multiplied for the purposes of this
// function. In other words, you can set a value in
// the range 0.0 to (length * loopcount).
////////////////////////////////////////////////////////////////////
void MovieTexture::
set_time(double t) {
CDWriter cdata(_cycler);
t = min(cdata->_video_length * cdata->_loop_count, max(0.0, t));
if (cdata->_playing) {
double now = ClockObject::get_global_clock()->get_frame_time();
cdata->_clock = t - (now * cdata->_play_rate);
} else {
cdata->_clock = t;
}
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::get_time
// Access: Published
// Description: Returns the current value of the movie's cursor.
// If the movie's loop count is greater than one, then
// its length is effectively multiplied for the
// purposes of this function. In other words,
// the return value will be in the range 0.0
// to (length * loopcount).
////////////////////////////////////////////////////////////////////
double MovieTexture::
get_time() const {
CDReader cdata(_cycler);
double clock = cdata->_clock;
if (cdata->_playing) {
double now = ClockObject::get_global_clock()->get_frame_time();
clock += (now * cdata->_play_rate);
}
return min(cdata->_video_length * cdata->_loop_count, clock);
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::set_loop
// Access: Published
// Description: If true, sets the movie's loop count to 1 billion.
// If false, sets the movie's loop count to one.
////////////////////////////////////////////////////////////////////
void MovieTexture::
set_loop(bool loop) {
CDWriter cdata(_cycler);
if (loop) {
cdata->_loop_count = 1000000000;
} else {
cdata->_loop_count = 1;
}
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::get_loop
// Access: Published
// Description: Returns true if the movie's loop count is not equal
// to one.
////////////////////////////////////////////////////////////////////
bool MovieTexture::
get_loop() const {
CDReader cdata(_cycler);
return (cdata->_loop_count != 1);
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::set_loop_count
// Access: Published
// Description: Sets the movie's loop count to the desired value.
////////////////////////////////////////////////////////////////////
void MovieTexture::
set_loop_count(int n) {
CDWriter cdata(_cycler);
if (n < 1) n = 1;
if (n > 1000000000) n = 1000000000;
cdata->_loop_count = n;
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::get_loop_count
// Access: Published
// Description: Returns the movie's loop count.
////////////////////////////////////////////////////////////////////
int MovieTexture::
get_loop_count() const {
CDReader cdata(_cycler);
return cdata->_loop_count;
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::set_play_rate
// Access: Published
// Description: Sets the movie's play-rate. This is the speed at
// which the movie's cursor advances. The default is
// to advance 1.0 movie-seconds per real-time second.
////////////////////////////////////////////////////////////////////
void MovieTexture::
set_play_rate(double rate) {
CDWriter cdata(_cycler);
if (cdata->_playing) {
double now = ClockObject::get_global_clock()->get_frame_time();
cdata->_clock += (now * cdata->_play_rate);
cdata->_play_rate = rate;
cdata->_clock -= (now * cdata->_play_rate);
} else {
cdata->_play_rate = rate;
}
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::get_play_rate
// Access: Published
// Description: Gets the movie's play-rate.
////////////////////////////////////////////////////////////////////
double MovieTexture::
get_play_rate() const {
CDReader cdata(_cycler);
return cdata->_play_rate;
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::is_playing
// Access: Published
// Description: Returns true if the movie's cursor is advancing.
////////////////////////////////////////////////////////////////////
bool MovieTexture::
is_playing() const {
CDReader cdata(_cycler);
return cdata->_playing;
}

View File

@ -42,6 +42,19 @@ PUBLISHED:
INLINE int get_video_height() const;
INLINE LVecBase2f get_tex_scale() const;
void restart();
void stop();
void play();
void set_time(double t);
double get_time() const;
void set_loop(bool enable);
bool get_loop() const;
void set_loop_count(int count);
int get_loop_count() const;
void set_play_rate(double play_rate);
double get_play_rate() const;
bool is_playing() const;
public:
static PT(Texture) make_texture();
virtual bool has_cull_callback() const;
@ -62,7 +75,6 @@ protected:
VideoPage();
PT(MovieVideo) _color;
PT(MovieVideo) _alpha;
double _base_clock;
};
typedef pvector<VideoPage> Pages;
@ -75,10 +87,16 @@ protected:
virtual TypeHandle get_parent_type() const {
return MovieTexture::get_class_type();
}
Pages _pages;
int _video_width;
int _video_height;
double _video_length;
double _clock;
bool _playing;
int _loop_count;
double _play_rate;
};
PipelineCycler<CData> _cycler;

View File

@ -60,12 +60,12 @@ FfmpegVideo(const Filename &name) :
if(_format_ctx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) {
_video_index = i;
_video_ctx = _format_ctx->streams[i]->codec;
_video_timebase = av_q2d(_video_ctx->time_base);
_video_timebase = av_q2d(_format_ctx->streams[i]->time_base);
}
if(_format_ctx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO) {
_audio_index = i;
_audio_ctx = _format_ctx->streams[i]->codec;
_audio_timebase = av_q2d(_audio_ctx->time_base);
_audio_timebase = av_q2d(_format_ctx->streams[i]->time_base);
}
}
@ -86,7 +86,7 @@ FfmpegVideo(const Filename &name) :
_size_x = _video_ctx->width;
_size_y = _video_ctx->height;
_num_components = (_video_ctx->pix_fmt==PIX_FMT_RGBA32) ? 4:3;
_num_components = 3; // Don't know how to implement RGBA movies yet.
if (_audio_ctx) {
AVCodec *pAudioCodec=avcodec_find_decoder(_audio_ctx->codec_id);
@ -100,10 +100,10 @@ FfmpegVideo(const Filename &name) :
}
}
}
_length = (_format_ctx->duration * 1.0) / AV_TIME_BASE;
_can_seek = true;
_can_seek_zero = true;
_can_seek_fast = true;
memset(_time_corrections, 0, sizeof(_time_corrections));
@ -135,6 +135,7 @@ FfmpegVideo::
////////////////////////////////////////////////////////////////////
void FfmpegVideo::
cleanup() {
_frame_out->data[0] = 0;
if (_format_ctx) {
av_close_input_file(_format_ctx);
_format_ctx = 0;
@ -217,12 +218,13 @@ read_ahead() {
}
}
cerr << "Audio: " << dts << " " << real << "\n";
cerr << "Audio: " << pkt.dts << "(" << dts << ") " << real << "\n";
}
av_free_packet(&pkt);
}
cerr << "Synthesized dummy frame.\n";
_next_start = _next_start + 1.0;
}
@ -232,11 +234,13 @@ read_ahead() {
// Description: See MovieVideo::fetch_into_buffer.
////////////////////////////////////////////////////////////////////
void FfmpegVideo::
fetch_into_buffer(double time, unsigned char *data, bool rgba) {
fetch_into_buffer(double time, unsigned char *data, bool bgra) {
// If there was an error at any point, fetch black.
if (_format_ctx==0) {
memset(data,0,size_x()*size_y()*(rgba?4:3));
memset(data,0,size_x()*size_y()*(bgra?4:3));
_last_start = _next_start;
_next_start += 1.0;
return;
}
@ -244,13 +248,15 @@ fetch_into_buffer(double time, unsigned char *data, bool rgba) {
nassertv(ctx->width == size_x());
nassertv(ctx->height == size_y());
if (rgba) {
avpicture_fill((AVPicture *)_frame_out, data, PIX_FMT_RGBA32, ctx->width, ctx->height);
img_convert((AVPicture *)_frame_out, PIX_FMT_RGBA32,
if (bgra) {
_frame_out->data[0] = data + ((ctx->height-1) * ctx->width * 4);
_frame_out->linesize[0] = ctx->width * -4;
img_convert((AVPicture *)_frame_out, PIX_FMT_BGRA,
(AVPicture *)_frame, ctx->pix_fmt, ctx->width, ctx->height);
} else {
avpicture_fill((AVPicture *)_frame_out, data, PIX_FMT_RGB24, ctx->width, ctx->height);
img_convert((AVPicture *)_frame_out, PIX_FMT_RGB24,
_frame_out->data[0] = data + ((ctx->height-1) * ctx->width * 3);
_frame_out->linesize[0] = ctx->width * -3;
img_convert((AVPicture *)_frame_out, PIX_FMT_BGR24,
(AVPicture *)_frame, ctx->pix_fmt, ctx->width, ctx->height);
}

View File

@ -72,7 +72,8 @@ InkblotVideo(int x, int y, int fps) :
_cells2 = new unsigned char[padx * pady];
memset(_cells, 255, padx * pady);
memset(_cells2, 255, padx * pady);
_can_seek = true;
_can_seek_fast = false;
_frames_read = 0;
}
@ -93,12 +94,12 @@ InkblotVideo::
// Description: See MovieVideo::fetch_into_buffer.
////////////////////////////////////////////////////////////////////
void InkblotVideo::
fetch_into_buffer(double time, unsigned char *data, bool rgba) {
fetch_into_buffer(double time, unsigned char *data, bool bgra) {
int padx = size_x() + 2;
int pady = size_y() + 2;
if ((time == 0.0)&&(_next_start != 0.0)) {
if (time < _next_start) {
// Rewind to beginning.
memset(_cells, 255, padx * pady);
memset(_cells2, 255, padx * pady);
@ -139,10 +140,10 @@ fetch_into_buffer(double time, unsigned char *data, bool rgba) {
color &c1 = colormap[(val>>4)+0];
color &c2 = colormap[(val>>4)+1];
int lerp = val & 15;
data[0] = (c1.r * (16-lerp) + c2.r * lerp) / 16;
data[0] = (c1.b * (16-lerp) + c2.b * lerp) / 16;
data[1] = (c1.g * (16-lerp) + c2.g * lerp) / 16;
data[2] = (c1.b * (16-lerp) + c2.b * lerp) / 16;
if (rgba) {
data[2] = (c1.r * (16-lerp) + c2.r * lerp) / 16;
if (bgra) {
data[3] = 255;
data += 4;
} else {

View File

@ -76,7 +76,14 @@ length() const {
////////////////////////////////////////////////////////////////////
// Function: MovieAudio::can_seek
// Access: Public
// Description: See method 'seek' for an explanation.
// Description: Returns true if the movie can seek. If this is
// true, seeking is still not guaranteed to be fast:
// for some movies, seeking is implemented by rewinding
// to the beginning and then fast-forwarding to the
// desired location. Even if the movie cannot seek,
// the seek method can still advance to an arbitrary
// location by reading samples and discarding them.
// However, to move backward, can_seek must return true.
////////////////////////////////////////////////////////////////////
INLINE bool MovieAudio::
can_seek() const {
@ -84,13 +91,13 @@ can_seek() const {
}
////////////////////////////////////////////////////////////////////
// Function: MovieAudio::can_seek_zero
// Function: MovieAudio::can_seek_fast
// Access: Public
// Description: See method 'seek' for an explanation.
// Description: Returns true if seek operations are constant time.
////////////////////////////////////////////////////////////////////
INLINE bool MovieAudio::
can_seek_zero() const {
return _can_seek_zero;
can_seek_fast() const {
return _can_seek_fast;
}
////////////////////////////////////////////////////////////////////

View File

@ -35,7 +35,7 @@ MovieAudio(const string &name) :
_audio_channels(1),
_length(1.0E10),
_can_seek(true),
_can_seek_zero(true),
_can_seek_fast(true),
_aborted(false),
_samples_read(0)
{
@ -77,22 +77,26 @@ read_samples(int n, PN_int16 *data) {
////////////////////////////////////////////////////////////////////
// Function: MovieAudio::seek
// Access: Published, Virtual
// Description: Skips to the specified point in the movie. After
// Description: Skips to the specified sample number. After
// calling seek, samples_read will be equal to the
// offset times the sample rate.
// specified value. If the movie reports that it
// cannot seek, then this method can still advance
// by reading samples and discarding them. However,
// to move backward, can_seek must be true.
//
// If the movie reports that it can_seek, it doesn't
// mean that it can do so quickly. It may have to
// rewind the movie and then fast forward to the
// desired location. Only if can_seek_fast returns
// true can seek operations be done in constant time.
//
// Seeking may not be precise, because AVI files
// often have inaccurate indices. However, it is
// usually pretty close (ie, 0.05 seconds).
//
// It is an error to call seek with a nonzero offset
// if can_seek() reports false. It is an error to
// call seek with a zero offset if can_seek_zero
// reports false.
////////////////////////////////////////////////////////////////////
void MovieAudio::
seek(double offset) {
_samples_read = offset * audio_rate();
seek(int sr) {
_samples_read = sr;
}
////////////////////////////////////////////////////////////////////

View File

@ -45,11 +45,11 @@ PUBLISHED:
INLINE int audio_channels() const;
INLINE double length() const;
INLINE bool can_seek() const;
INLINE bool can_seek_zero() const;
INLINE bool can_seek_fast() const;
INLINE bool aborted() const;
INLINE int samples_read() const;
INLINE void skip_samples(int n);
virtual void seek(double offset);
virtual void seek(int sr);
virtual PT(MovieAudio) make_copy() const;
static PT(MovieAudio) load(const Filename &name);
@ -61,7 +61,7 @@ protected:
int _audio_channels;
double _length;
bool _can_seek;
bool _can_seek_zero;
bool _can_seek_fast;
bool _aborted;
int _samples_read;

View File

@ -86,7 +86,14 @@ length() const {
////////////////////////////////////////////////////////////////////
// Function: MovieVideo::can_seek
// Access: Published
// Description: See explanation in fetch_to_buffer.
// Description: Returns true if the movie can seek. If this is
// true, seeking is still not guaranteed to be fast:
// for some movies, seeking is implemented by rewinding
// to the beginning and then fast-forwarding to the
// desired location. Even if the movie cannot seek,
// the fetch methods can still advance to an arbitrary
// location by reading frames and discarding them.
// However, to move backward, can_seek must return true.
////////////////////////////////////////////////////////////////////
INLINE bool MovieVideo::
can_seek() const {
@ -94,13 +101,13 @@ can_seek() const {
}
////////////////////////////////////////////////////////////////////
// Function: MovieVideo::can_seek_zero
// Function: MovieVideo::can_seek_fast
// Access: Published
// Description: See explanation in fetch_to_buffer.
// Description: Returns true if seek operations are constant time.
////////////////////////////////////////////////////////////////////
INLINE bool MovieVideo::
can_seek_zero() const {
return _can_seek_zero;
can_seek_fast() const {
return _can_seek_fast;
}
////////////////////////////////////////////////////////////////////

View File

@ -38,7 +38,7 @@ MovieVideo(const string &name) :
_num_components(3),
_length(1.0E10),
_can_seek(true),
_can_seek_zero(true),
_can_seek_fast(true),
_aborted(false),
_last_start(-1.0),
_next_start(0.0)
@ -242,19 +242,22 @@ fetch_into_texture_rgb(double time, Texture *t, int page) {
// Function: MovieVideo::fetch_into_buffer
// Access: Published, Virtual
// Description: Reads the specified video frame into the supplied
// RGB8 or RGBA8 buffer. The frame's begin and end
// BGR or BGRA buffer. The frame's begin and end
// times are stored in last_start and next_start.
//
// You may always specify a timestamp greater than or
// equal to next_start --- ie, read forward through the
// movie. If the movie reports that it can_seek_zero,
// you may also specify a timestamp of 0.0 --- ie,
// rewind the movie. If the movie reports that it
// can_seek, you may specify any timestamp. It is
// generally much faster to read frames sequentially.
// If the movie reports that it can_seek, you may
// also specify a timestamp less than next_start.
// Otherwise, you may only specify a timestamp
// greater than or equal to next_start.
//
// If the movie reports that it can_seek, it doesn't
// mean that it can do so quickly. It may have to
// rewind the movie and then fast forward to the
// desired location. Only if can_seek_fast returns
// true can it seek rapidly.
////////////////////////////////////////////////////////////////////
void MovieVideo::
fetch_into_buffer(double time, unsigned char *data, bool rgba) {
fetch_into_buffer(double time, unsigned char *data, bool bgra) {
// The following is the implementation of the null video stream, ie,
// a stream of blinking red and blue frames. This method must be
@ -272,7 +275,7 @@ fetch_into_buffer(double time, unsigned char *data, bool rgba) {
data[1] = 128;
data[2] = 255;
}
if (rgba) {
if (bgra) {
data[3] = 255;
}
}

View File

@ -45,7 +45,7 @@ class EXPCL_PANDA_MOVIES MovieVideo : public TypedWritableReferenceCount, public
INLINE int get_num_components() const;
INLINE int length() const;
INLINE bool can_seek() const;
INLINE bool can_seek_zero() const;
INLINE bool can_seek_fast() const;
INLINE bool aborted() const;
INLINE double last_start() const;
INLINE double next_start() const;
@ -57,7 +57,7 @@ class EXPCL_PANDA_MOVIES MovieVideo : public TypedWritableReferenceCount, public
static PT(MovieVideo) load(const Filename &name);
public:
virtual void fetch_into_buffer(double time, unsigned char *block, bool rgba);
virtual void fetch_into_buffer(double time, unsigned char *block, bool bgra);
private:
void allocate_conversion_buffer();
@ -69,7 +69,7 @@ class EXPCL_PANDA_MOVIES MovieVideo : public TypedWritableReferenceCount, public
int _num_components;
double _length;
bool _can_seek;
bool _can_seek_zero;
bool _can_seek_fast;
bool _aborted;
double _last_start;
double _next_start;