Browse Source

ffmpeg-global-lock

David Rose 14 years ago
parent
commit
f6a0af6f8d

+ 10 - 0
panda/src/movies/config_movies.cxx

@@ -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 "

+ 1 - 0
panda/src/movies/config_movies.h

@@ -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();

+ 67 - 22
panda/src/movies/ffmpegVideoCursor.cxx

@@ -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
-      avcodec_decode_video(_video_ctx, _frame,
-                           &finished, _packet1->data, _packet1->size);
-#else
-      avcodec_decode_video2(_video_ctx, _frame, &finished, _packet1);
-#endif
+      decode_frame(finished, _packet1);
       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
-    avcodec_decode_video(_video_ctx, _frame,
-                         &finished, _packet1->data, _packet1->size);
-#else
-    avcodec_decode_video2(_video_ctx, _frame, &finished, _packet1);
-#endif
+    decode_frame(finished, _packet1);
     
     
   } 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
-      avcodec_decode_video(_video_ctx, _frame,
-                           &finished, _packet0->data, _packet0->size);
-#else
-      avcodec_decode_video2(_video_ctx, _frame, &finished, _packet0);
-#endif
+      decode_frame(finished, _packet0);
       _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);
-  sws_scale(_convert_ctx, _frame->data, _frame->linesize, 0, _size_y, _frame_out->data, _frame_out->linesize);
+    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
 #else
-  img_convert((AVPicture *)_frame_out, PIX_FMT_BGR24, 
-              (AVPicture *)_frame, _video_ctx->pix_fmt, _size_x, _size_y);
+    img_convert((AVPicture *)_frame_out, PIX_FMT_BGR24, 
+                (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
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 3 - 0
panda/src/movies/ffmpegVideoCursor.h

@@ -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);