ffmpeg-global-lock

This commit is contained in:
David Rose 2011-11-17 01:23:06 +00:00
parent 5d00998747
commit f6a0af6f8d
4 changed files with 81 additions and 22 deletions

View File

@ -58,6 +58,16 @@ ConfigVariableBool ffmpeg_support_seek
"which can be much slower. Set this false only if you suspect " "which can be much slower. Set this false only if you suspect "
"a problem with av_seek_frame().")); "a problem with av_seek_frame()."));
ConfigVariableBool ffmpeg_global_lock
("ffmpeg-global-lock", false,
PRC_DESC("Set this true to enable a single global mutex across *all* ffmpeg "
"operations. Leave this false to use the mutex only for "
"the ffmpeg operations that are generally known to be "
"not thread-safe. This will negatively affect ffmpeg performance, "
"especially when decoding multiple videos at once (including the "
"left and right channels of a stereo video). Set this true only "
"if you suspect a problem with ffmpeg's own thread-safe nature."));
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 start ffmpeg decoder " PRC_DESC("The default thread priority at which to start ffmpeg decoder "

View File

@ -29,6 +29,7 @@ NotifyCategoryDecl(ffmpeg, EXPCL_PANDA_MOVIES, EXPTP_PANDA_MOVIES);
extern ConfigVariableInt ffmpeg_max_readahead_frames; extern ConfigVariableInt ffmpeg_max_readahead_frames;
extern ConfigVariableBool ffmpeg_support_seek; extern ConfigVariableBool ffmpeg_support_seek;
extern ConfigVariableBool ffmpeg_global_lock;
extern ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority; extern ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority;
extern EXPCL_PANDA_MOVIES void init_libmovies(); extern EXPCL_PANDA_MOVIES void init_libmovies();

View File

@ -827,6 +827,22 @@ do_recycle_all_frames() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool FfmpegVideoCursor:: bool FfmpegVideoCursor::
fetch_packet(int default_frame) { fetch_packet(int default_frame) {
if (ffmpeg_global_lock) {
ReMutexHolder av_holder(_av_lock);
return do_fetch_packet(default_frame);
} else {
return do_fetch_packet(default_frame);
}
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideoCursor::do_fetch_packet
// Access: Private
// Description: As above, with the ffmpeg global lock held (if
// configured on).
////////////////////////////////////////////////////////////////////
bool FfmpegVideoCursor::
do_fetch_packet(int default_frame) {
if (_packet0->data) { if (_packet0->data) {
av_free_packet(_packet0); av_free_packet(_packet0);
} }
@ -906,12 +922,7 @@ fetch_frame(int frame) {
PStatTimer timer(seek_pcollector); PStatTimer timer(seek_pcollector);
// Decode and discard the previous packet. // Decode and discard the previous packet.
#if LIBAVCODEC_VERSION_INT < 3414272 decode_frame(finished, _packet1);
avcodec_decode_video(_video_ctx, _frame,
&finished, _packet1->data, _packet1->size);
#else
avcodec_decode_video2(_video_ctx, _frame, &finished, _packet1);
#endif
flip_packets(); flip_packets();
_begin_frame = _packet_frame; _begin_frame = _packet_frame;
if (fetch_packet(frame)) { if (fetch_packet(frame)) {
@ -925,23 +936,13 @@ fetch_frame(int frame) {
// At this point, _packet0 contains the *next* packet to be // At this point, _packet0 contains the *next* packet to be
// decoded next frame, and _packet1 contains the packet to decode // decoded next frame, and _packet1 contains the packet to decode
// for this frame. // for this frame.
#if LIBAVCODEC_VERSION_INT < 3414272 decode_frame(finished, _packet1);
avcodec_decode_video(_video_ctx, _frame,
&finished, _packet1->data, _packet1->size);
#else
avcodec_decode_video2(_video_ctx, _frame, &finished, _packet1);
#endif
} else { } else {
// Just get the next frame. // Just get the next frame.
finished = 0; finished = 0;
while (!finished && _packet0->data) { while (!finished && _packet0->data) {
#if LIBAVCODEC_VERSION_INT < 3414272 decode_frame(finished, _packet0);
avcodec_decode_video(_video_ctx, _frame,
&finished, _packet0->data, _packet0->size);
#else
avcodec_decode_video2(_video_ctx, _frame, &finished, _packet0);
#endif
_begin_frame = _packet_frame; _begin_frame = _packet_frame;
fetch_packet(_begin_frame + 1); fetch_packet(_begin_frame + 1);
} }
@ -951,6 +952,38 @@ fetch_frame(int frame) {
_frame_ready = true; _frame_ready = true;
} }
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideoCursor::decode_frame
// Access: Private
// Description: Called within the sub-thread. Decodes the data in
// the specified packet into _frame.
////////////////////////////////////////////////////////////////////
void FfmpegVideoCursor::
decode_frame(int &finished, AVPacket *packet) {
if (ffmpeg_global_lock) {
ReMutexHolder av_holder(_av_lock);
do_decode_frame(finished, packet);
} else {
do_decode_frame(finished, packet);
}
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideoCursor::do_decode_frame
// Access: Private
// Description: As above, with the ffmpeg global lock held (if
// configured on).
////////////////////////////////////////////////////////////////////
void FfmpegVideoCursor::
do_decode_frame(int &finished, AVPacket *packet) {
#if LIBAVCODEC_VERSION_INT < 3414272
avcodec_decode_video(_video_ctx, _frame,
&finished, packet->data, packet->size);
#else
avcodec_decode_video2(_video_ctx, _frame, &finished, packet);
#endif
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: FfmpegVideoCursor::seek // Function: FfmpegVideoCursor::seek
// Access: Private // Access: Private
@ -1182,13 +1215,25 @@ export_frame(FfmpegBuffer *buffer) {
_frame_out->linesize[0] = _size_x * -3; _frame_out->linesize[0] = _size_x * -3;
buffer->_begin_frame = _begin_frame; buffer->_begin_frame = _begin_frame;
buffer->_end_frame = _end_frame; buffer->_end_frame = _end_frame;
if (ffmpeg_global_lock) {
ReMutexHolder av_holder(_av_lock);
#ifdef HAVE_SWSCALE #ifdef HAVE_SWSCALE
nassertv(_convert_ctx != NULL && _frame != NULL && _frame_out != NULL); nassertv(_convert_ctx != NULL && _frame != NULL && _frame_out != NULL);
sws_scale(_convert_ctx, _frame->data, _frame->linesize, 0, _size_y, _frame_out->data, _frame_out->linesize); sws_scale(_convert_ctx, _frame->data, _frame->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);
#endif #endif
} else {
#ifdef HAVE_SWSCALE
nassertv(_convert_ctx != NULL && _frame != NULL && _frame_out != NULL);
sws_scale(_convert_ctx, _frame->data, _frame->linesize, 0, _size_y, _frame_out->data, _frame_out->linesize);
#else
img_convert((AVPicture *)_frame_out, PIX_FMT_BGR24,
(AVPicture *)_frame, _video_ctx->pix_fmt, _size_x, _size_y);
#endif
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -124,8 +124,11 @@ private:
void do_recycle_all_frames(); void do_recycle_all_frames();
bool fetch_packet(int default_frame); bool fetch_packet(int default_frame);
bool do_fetch_packet(int default_frame);
void flip_packets(); void flip_packets();
void fetch_frame(int frame); void fetch_frame(int frame);
void decode_frame(int &finished, AVPacket *packet);
void do_decode_frame(int &finished, AVPacket *packet);
void seek(int frame, bool backward); void seek(int frame, bool backward);
int binary_seek(int min_frame, int max_frame, int target_frame, int num_iterations); int binary_seek(int min_frame, int max_frame, int target_frame, int num_iterations);
void advance_to_frame(int frame); void advance_to_frame(int frame);