mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
further fixes
This commit is contained in:
parent
3262f702a3
commit
9f5d8a9548
@ -45,15 +45,15 @@ ConfigureFn(config_movies) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConfigVariableInt ffmpeg_max_readahead_frames
|
ConfigVariableInt ffmpeg_max_readahead_frames
|
||||||
("ffmpeg-max-readahead-frames", 10,
|
("ffmpeg-max-readahead-frames", 2,
|
||||||
PRC_DESC("The maximum number of frames ahead which an ffmpeg decoder thread "
|
PRC_DESC("The maximum number of frames ahead which an ffmpeg decoder thread "
|
||||||
"should read in advance of actual playback. Set this to 0 to "
|
"should read in advance of actual playback. Set this to 0 to "
|
||||||
"decode ffmpeg videos in the main thread."));
|
"decode ffmpeg videos in the main thread."));
|
||||||
|
|
||||||
ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority
|
ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority
|
||||||
("ffmpeg-thread-priority", TP_normal,
|
("ffmpeg-thread-priority", TP_normal,
|
||||||
PRC_DESC("The default thread priority at which to run the ffmpeg decoder thread "
|
PRC_DESC("The default thread priority at which to start ffmpeg decoder "
|
||||||
"for a given video texture."));
|
"threads."));
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: init_libmovies
|
// Function: init_libmovies
|
||||||
|
@ -25,8 +25,10 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
#include "pStatCollector.h"
|
#include "pStatCollector.h"
|
||||||
#include "pStatTimer.h"
|
#include "pStatTimer.h"
|
||||||
|
#include "mutexHolder.h"
|
||||||
|
#include "reMutexHolder.h"
|
||||||
|
|
||||||
Mutex FfmpegVideoCursor::_av_lock;
|
ReMutex FfmpegVideoCursor::_av_lock;
|
||||||
TypeHandle FfmpegVideoCursor::_type_handle;
|
TypeHandle FfmpegVideoCursor::_type_handle;
|
||||||
|
|
||||||
|
|
||||||
@ -74,6 +76,10 @@ init_from(FfmpegVideo *source) {
|
|||||||
_source = source;
|
_source = source;
|
||||||
_filename = _source->get_filename();
|
_filename = _source->get_filename();
|
||||||
|
|
||||||
|
// Hold the global lock while we open the file and create avcodec
|
||||||
|
// objects.
|
||||||
|
ReMutexHolder av_holder(_av_lock);
|
||||||
|
|
||||||
if (!_source->get_subfile_info().is_empty()) {
|
if (!_source->get_subfile_info().is_empty()) {
|
||||||
// Read a subfile.
|
// Read a subfile.
|
||||||
if (!_ffvfile.open_subfile(_source->get_subfile_info())) {
|
if (!_ffvfile.open_subfile(_source->get_subfile_info())) {
|
||||||
@ -119,42 +125,41 @@ init_from(FfmpegVideo *source) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
AVCodec *pVideoCodec = avcodec_find_decoder(_video_ctx->codec_id);
|
||||||
MutexHolder av_holder(_av_lock);
|
if (pVideoCodec == NULL) {
|
||||||
AVCodec *pVideoCodec = avcodec_find_decoder(_video_ctx->codec_id);
|
movies_cat.info()
|
||||||
if (pVideoCodec == NULL) {
|
<< "Couldn't find codec\n";
|
||||||
movies_cat.info()
|
cleanup();
|
||||||
<< "Couldn't find codec\n";
|
return;
|
||||||
cleanup();
|
}
|
||||||
return;
|
if (avcodec_open(_video_ctx, pVideoCodec) < 0) {
|
||||||
}
|
movies_cat.info()
|
||||||
if (avcodec_open(_video_ctx, pVideoCodec) < 0) {
|
<< "Couldn't open codec\n";
|
||||||
movies_cat.info()
|
cleanup();
|
||||||
<< "Couldn't open codec\n";
|
return;
|
||||||
cleanup();
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_size_x = _video_ctx->width;
|
_size_x = _video_ctx->width;
|
||||||
_size_y = _video_ctx->height;
|
_size_y = _video_ctx->height;
|
||||||
_num_components = 3; // Don't know how to implement RGBA movies yet.
|
_num_components = 3; // Don't know how to implement RGBA movies yet.
|
||||||
_length = (_format_ctx->duration * 1.0) / AV_TIME_BASE;
|
_length = (_format_ctx->duration * 1.0) / AV_TIME_BASE;
|
||||||
_can_seek = true;
|
_can_seek = true;
|
||||||
_can_seek_fast = true;
|
_can_seek_fast = true;
|
||||||
|
|
||||||
#ifdef HAVE_SWSCALE
|
#ifdef HAVE_SWSCALE
|
||||||
_convert_ctx = sws_getContext(_size_x, _size_y,
|
_convert_ctx = sws_getContext(_size_x, _size_y,
|
||||||
_video_ctx->pix_fmt, _size_x, _size_y,
|
_video_ctx->pix_fmt, _size_x, _size_y,
|
||||||
PIX_FMT_BGR24, SWS_FAST_BILINEAR, NULL, NULL, NULL);
|
PIX_FMT_BGR24, SWS_BILINEAR | SWS_PRINT_INFO, NULL, NULL, NULL);
|
||||||
#endif // HAVE_SWSCALE
|
#endif // HAVE_SWSCALE
|
||||||
}
|
|
||||||
|
|
||||||
_frame = avcodec_alloc_frame();
|
_frame = avcodec_alloc_frame();
|
||||||
_frame_out = avcodec_alloc_frame();
|
_frame_out = avcodec_alloc_frame();
|
||||||
|
|
||||||
if ((_frame == 0)||(_frame_out == 0)) {
|
if ((_frame == 0)||(_frame_out == 0)) {
|
||||||
cleanup();
|
cleanup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_packet0 = new AVPacket;
|
_packet0 = new AVPacket;
|
||||||
_packet1 = new AVPacket;
|
_packet1 = new AVPacket;
|
||||||
memset(_packet0, 0, sizeof(AVPacket));
|
memset(_packet0, 0, sizeof(AVPacket));
|
||||||
@ -162,9 +167,7 @@ init_from(FfmpegVideo *source) {
|
|||||||
|
|
||||||
fetch_packet(0.0);
|
fetch_packet(0.0);
|
||||||
_initial_dts = _packet0->dts;
|
_initial_dts = _packet0->dts;
|
||||||
_packet_time = 0.0;
|
fetch_frame(-1);
|
||||||
_begin_time = -1.0;
|
|
||||||
_end_time = 0.0;
|
|
||||||
|
|
||||||
#ifdef HAVE_THREADS
|
#ifdef HAVE_THREADS
|
||||||
set_max_readahead_frames(ffmpeg_max_readahead_frames);
|
set_max_readahead_frames(ffmpeg_max_readahead_frames);
|
||||||
@ -398,10 +401,11 @@ fetch_buffer(double time) {
|
|||||||
Buffer *frame = NULL;
|
Buffer *frame = NULL;
|
||||||
if (_thread_status == TS_stopped) {
|
if (_thread_status == TS_stopped) {
|
||||||
// Non-threaded case. Just get the next frame directly.
|
// Non-threaded case. Just get the next frame directly.
|
||||||
frame = do_alloc_frame();
|
|
||||||
|
|
||||||
fetch_time(time);
|
fetch_time(time);
|
||||||
export_frame(frame);
|
if (_frame_ready) {
|
||||||
|
frame = do_alloc_frame();
|
||||||
|
export_frame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Threaded case. Wait for the thread to serve up the required
|
// Threaded case. Wait for the thread to serve up the required
|
||||||
@ -474,6 +478,9 @@ void FfmpegVideoCursor::
|
|||||||
cleanup() {
|
cleanup() {
|
||||||
stop_thread();
|
stop_thread();
|
||||||
|
|
||||||
|
// Hold the global lock while we free avcodec objects.
|
||||||
|
ReMutexHolder av_holder(_av_lock);
|
||||||
|
|
||||||
if (_frame) {
|
if (_frame) {
|
||||||
av_free(_frame);
|
av_free(_frame);
|
||||||
_frame = NULL;
|
_frame = NULL;
|
||||||
@ -501,25 +508,21 @@ cleanup() {
|
|||||||
_packet1 = NULL;
|
_packet1 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
MutexHolder av_holder(_av_lock);
|
|
||||||
|
|
||||||
#ifdef HAVE_SWSCALE
|
#ifdef HAVE_SWSCALE
|
||||||
if (_convert_ctx != NULL) {
|
if (_convert_ctx != NULL) {
|
||||||
sws_freeContext(_convert_ctx);
|
sws_freeContext(_convert_ctx);
|
||||||
}
|
}
|
||||||
_convert_ctx = NULL;
|
_convert_ctx = NULL;
|
||||||
#endif // HAVE_SWSCALE
|
#endif // HAVE_SWSCALE
|
||||||
|
|
||||||
if ((_video_ctx)&&(_video_ctx->codec)) {
|
if ((_video_ctx)&&(_video_ctx->codec)) {
|
||||||
avcodec_close(_video_ctx);
|
avcodec_close(_video_ctx);
|
||||||
}
|
}
|
||||||
_video_ctx = NULL;
|
_video_ctx = NULL;
|
||||||
|
|
||||||
if (_format_ctx) {
|
if (_format_ctx) {
|
||||||
_ffvfile.close();
|
_ffvfile.close();
|
||||||
_format_ctx = NULL;
|
_format_ctx = NULL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_video_index = -1;
|
_video_index = -1;
|
||||||
@ -597,9 +600,15 @@ do_poll() {
|
|||||||
nassertr(frame != NULL, false);
|
nassertr(frame != NULL, false);
|
||||||
_lock.release();
|
_lock.release();
|
||||||
fetch_frame(-1);
|
fetch_frame(-1);
|
||||||
export_frame(frame);
|
if (_frame_ready) {
|
||||||
_lock.acquire();
|
export_frame(frame);
|
||||||
_readahead_frames.push_back(frame);
|
_lock.acquire();
|
||||||
|
_readahead_frames.push_back(frame);
|
||||||
|
} else {
|
||||||
|
// No frame.
|
||||||
|
_lock.acquire();
|
||||||
|
do_recycle_frame(frame);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,10 +624,17 @@ do_poll() {
|
|||||||
nassertr(frame != NULL, false);
|
nassertr(frame != NULL, false);
|
||||||
_lock.release();
|
_lock.release();
|
||||||
fetch_time(seek_time);
|
fetch_time(seek_time);
|
||||||
export_frame(frame);
|
if (_frame_ready) {
|
||||||
_lock.acquire();
|
export_frame(frame);
|
||||||
do_recycle_all_frames();
|
_lock.acquire();
|
||||||
_readahead_frames.push_back(frame);
|
do_recycle_all_frames();
|
||||||
|
_readahead_frames.push_back(frame);
|
||||||
|
} else {
|
||||||
|
_lock.acquire();
|
||||||
|
do_recycle_all_frames();
|
||||||
|
do_recycle_frame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
if (_thread_status == TS_seeking) {
|
if (_thread_status == TS_seeking) {
|
||||||
// After seeking, we automatically transition to readahead.
|
// After seeking, we automatically transition to readahead.
|
||||||
_thread_status = TS_readahead;
|
_thread_status = TS_readahead;
|
||||||
@ -752,8 +768,11 @@ fetch_frame(double time) {
|
|||||||
// Get the next packet. The first packet beyond the time we're
|
// Get the next packet. The first packet beyond the time we're
|
||||||
// looking for marks the point to stop.
|
// looking for marks the point to stop.
|
||||||
if (fetch_packet(time)) {
|
if (fetch_packet(time)) {
|
||||||
ffmpeg_cat.debug()
|
if (ffmpeg_cat.is_debug()) {
|
||||||
<< "end of video\n";
|
ffmpeg_cat.debug()
|
||||||
|
<< "end of video\n";
|
||||||
|
}
|
||||||
|
_frame_ready = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
while (_packet_time <= time) {
|
while (_packet_time <= time) {
|
||||||
@ -766,8 +785,11 @@ fetch_frame(double time) {
|
|||||||
#endif
|
#endif
|
||||||
flip_packets();
|
flip_packets();
|
||||||
if (fetch_packet(time)) {
|
if (fetch_packet(time)) {
|
||||||
ffmpeg_cat.debug()
|
if (ffmpeg_cat.is_debug()) {
|
||||||
<< "end of video\n";
|
ffmpeg_cat.debug()
|
||||||
|
<< "end of video\n";
|
||||||
|
}
|
||||||
|
_frame_ready = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -798,8 +820,8 @@ fetch_frame(double time) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_end_time = _packet_time;
|
_end_time = _packet_time;
|
||||||
|
_frame_ready = true;
|
||||||
return (finished != 0);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -829,7 +851,9 @@ seek(double t) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
MutexHolder av_holder(_av_lock);
|
// Hold the global lock while we close and re-open the video
|
||||||
|
// stream.
|
||||||
|
ReMutexHolder av_holder(_av_lock);
|
||||||
|
|
||||||
avcodec_close(_video_ctx);
|
avcodec_close(_video_ctx);
|
||||||
AVCodec *pVideoCodec = avcodec_find_decoder(_video_ctx->codec_id);
|
AVCodec *pVideoCodec = avcodec_find_decoder(_video_ctx->codec_id);
|
||||||
@ -845,9 +869,12 @@ seek(double t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fetch_packet(t);
|
fetch_packet(t);
|
||||||
|
fetch_frame(-1);
|
||||||
|
/*
|
||||||
if (_packet_time > t) {
|
if (_packet_time > t) {
|
||||||
_packet_time = t;
|
_packet_time = t;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -940,14 +967,19 @@ export_frame(MovieVideoCursor::Buffer *buffer) {
|
|||||||
static PStatCollector export_frame_collector("*:FFMPEG Convert Video to BGR");
|
static PStatCollector export_frame_collector("*:FFMPEG Convert Video to BGR");
|
||||||
PStatTimer timer(export_frame_collector);
|
PStatTimer timer(export_frame_collector);
|
||||||
|
|
||||||
|
if (!_frame_ready) {
|
||||||
|
// No frame data ready, just fill with black.
|
||||||
|
memset(buffer->_block, 0, buffer->_block_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_frame_out->data[0] = buffer->_block + ((_size_y - 1) * _size_x * 3);
|
_frame_out->data[0] = buffer->_block + ((_size_y - 1) * _size_x * 3);
|
||||||
_frame_out->linesize[0] = _size_x * -3;
|
_frame_out->linesize[0] = _size_x * -3;
|
||||||
buffer->_begin_time = _begin_time;
|
buffer->_begin_time = _begin_time;
|
||||||
buffer->_end_time = _end_time;
|
buffer->_end_time = _end_time;
|
||||||
#ifdef HAVE_SWSCALE
|
#ifdef HAVE_SWSCALE
|
||||||
nassertv(_convert_ctx != NULL);
|
nassertv(_convert_ctx != NULL && _frame != NULL && _frame_out != NULL);
|
||||||
sws_scale(_convert_ctx, _frame->data, _frame->linesize,
|
sws_scale(_convert_ctx, _frame->data, _frame->linesize, 0, _size_y, _frame_out->data, _frame_out->linesize);
|
||||||
0, _size_y, _frame_out->data, _frame_out->linesize);
|
|
||||||
#else
|
#else
|
||||||
img_convert((AVPicture *)_frame_out, PIX_FMT_BGR24,
|
img_convert((AVPicture *)_frame_out, PIX_FMT_BGR24,
|
||||||
(AVPicture *)_frame, _video_ctx->pix_fmt, _size_x, _size_y);
|
(AVPicture *)_frame, _video_ctx->pix_fmt, _size_x, _size_y);
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "genericThread.h"
|
#include "genericThread.h"
|
||||||
#include "threadPriority.h"
|
#include "threadPriority.h"
|
||||||
#include "pmutex.h"
|
#include "pmutex.h"
|
||||||
|
#include "reMutex.h"
|
||||||
#include "conditionVar.h"
|
#include "conditionVar.h"
|
||||||
|
|
||||||
struct AVFormatContext;
|
struct AVFormatContext;
|
||||||
@ -72,7 +73,7 @@ private:
|
|||||||
PT(GenericThread) _thread;
|
PT(GenericThread) _thread;
|
||||||
|
|
||||||
// This global Mutex protects calls to avcodec_open/close/etc.
|
// This global Mutex protects calls to avcodec_open/close/etc.
|
||||||
static Mutex _av_lock;
|
static ReMutex _av_lock;
|
||||||
|
|
||||||
// Protects _readahead_frames, _recycled_buffers, and all the
|
// Protects _readahead_frames, _recycled_buffers, and all the
|
||||||
// immediately following members.
|
// immediately following members.
|
||||||
@ -128,6 +129,7 @@ private:
|
|||||||
double _min_fseek;
|
double _min_fseek;
|
||||||
double _begin_time;
|
double _begin_time;
|
||||||
double _end_time;
|
double _end_time;
|
||||||
|
bool _frame_ready;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void register_with_read_factory();
|
static void register_with_read_factory();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user