Forráskód Böngészése

further attempts to fix ffmpeg. sheesh.

David Rose 14 éve
szülő
commit
9a810db5d2

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

@@ -50,6 +50,14 @@ ConfigVariableInt ffmpeg_max_readahead_frames
           "should read in advance of actual playback.  Set this to 0 to "
           "decode ffmpeg videos in the main thread."));
 
+ConfigVariableBool ffmpeg_support_seek
+("ffmpeg-support-seek", true,
+ PRC_DESC("True to use the av_seek_frame() function to seek within ffmpeg "
+          "video files.  If this is false, Panda will only seek within a "
+          "file by reading it from the beginning until the desired point, "
+          "which can be much slower.  Set this false only if you suspect "
+          "a problem with av_seek_frame()."));
+
 ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority
 ("ffmpeg-thread-priority", TP_normal,
  PRC_DESC("The default thread priority at which to start ffmpeg decoder "

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

@@ -19,6 +19,7 @@
 #include "notifyCategoryProxy.h"
 #include "configVariableEnum.h"
 #include "configVariableInt.h"
+#include "configVariableBool.h"
 #include "threadPriority.h"
 #include "dconfig.h"
 
@@ -27,6 +28,7 @@ NotifyCategoryDecl(movies, EXPCL_PANDA_MOVIES, EXPTP_PANDA_MOVIES);
 NotifyCategoryDecl(ffmpeg, EXPCL_PANDA_MOVIES, EXPTP_PANDA_MOVIES);
 
 extern ConfigVariableInt ffmpeg_max_readahead_frames;
+extern ConfigVariableBool ffmpeg_support_seek;
 extern ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority;
 
 extern EXPCL_PANDA_MOVIES void init_libmovies();

+ 51 - 53
panda/src/movies/ffmpegVideoCursor.cxx

@@ -104,8 +104,8 @@ init_from(FfmpegVideo *source) {
   memset(_packet1, 0, sizeof(AVPacket));
   
   fetch_packet(0);
-  _initial_dts = _packet0->dts;
   fetch_frame(-1);
+  _initial_dts = _begin_frame;
 
   _current_frame = -1;
   _eof_known = false;
@@ -341,7 +341,10 @@ set_time(double time, int loop_count) {
     }
   }
 
-  if (ffmpeg_cat.is_spam() /* && frame != _current_frame*/) {
+  // No point in trying to position before the first frame.
+  frame = max(frame, _initial_dts);
+
+  if (ffmpeg_cat.is_spam() && frame != _current_frame) {
     ffmpeg_cat.spam()
       << "set_time(" << time << "): " << frame << ", loop_count = " << loop_count << "\n";
   }
@@ -655,8 +658,16 @@ thread_main() {
     ffmpeg_cat.spam()
       << "ffmpeg thread for " << _filename.get_basename() << " starting.\n";
   }
+
+  // First, push the first frame onto the readahead queue.
+  if (_frame_ready) {
+    PT(FfmpegBuffer) frame = do_alloc_frame();
+    export_frame(frame);
+    MutexHolder holder(_lock);
+    _readahead_frames.push_back(frame);
+  }
   
-  // Repeatedly wait for something interesting to do, until we're told
+  // Now repeatedly wait for something interesting to do, until we're told
   // to shut down.
   while (_thread_status != TS_shutdown) {
     nassertv(_thread_status != TS_stopped);
@@ -952,66 +963,54 @@ seek(int frame, bool backward) {
   static PStatCollector seek_pcollector("*:FFMPEG Video Decoding:Seek");
   PStatTimer timer(seek_pcollector);
 
-  // Protect the call to av_seek_frame() in a global lock, just to be
-  // paranoid.
-  ReMutexHolder av_holder(_av_lock);
-
-  PN_int64 target_ts = (PN_int64)frame;
-  if (target_ts < (PN_int64)(_initial_dts)) {
-    // Attempts to seek before the first packet will fail.
-    target_ts = _initial_dts;
-  }
-  int flags = 0;
-  if (backward) {
-    flags = AVSEEK_FLAG_BACKWARD;
-    //reset_stream();
-  }
-
-  if (av_seek_frame(_format_ctx, _video_index, target_ts, flags) < 0) {
-    if (ffmpeg_cat.is_spam()) {
-      ffmpeg_cat.spam()
-        << "Seek failure.\n";
+  if (ffmpeg_support_seek) {
+    // Protect the call to av_seek_frame() in a global lock, just to be
+    // paranoid.
+    ReMutexHolder av_holder(_av_lock);
+    
+    PN_int64 target_ts = (PN_int64)frame;
+    if (target_ts < (PN_int64)(_initial_dts)) {
+      // Attempts to seek before the first packet will fail.
+      target_ts = _initial_dts;
     }
-
+    int flags = 0;
     if (backward) {
-      // Now try to seek forward.
-      reset_stream();
-      return seek(frame, false);
+      flags = AVSEEK_FLAG_BACKWARD;
     }
-
-    // Try a binary search to get a little closer.
-    if (binary_seek(_initial_dts, frame, frame, 1) < 0) {
+    
+    if (av_seek_frame(_format_ctx, _video_index, target_ts, flags) < 0) {
       if (ffmpeg_cat.is_spam()) {
         ffmpeg_cat.spam()
-          << "Seek double failure.\n";
+          << "Seek failure.\n";
+      }
+      
+      if (backward) {
+        // Now try to seek forward.
+        reset_stream();
+        seek(frame, false);
+        return;
+      }
+      
+      // Try a binary search to get a little closer.
+      if (binary_seek(_initial_dts, frame, frame, 1) < 0) {
+        if (ffmpeg_cat.is_spam()) {
+          ffmpeg_cat.spam()
+            << "Seek double failure.\n";
+        }
+        reset_stream();
+        return;
       }
-      reset_stream();
     }
-  }
-
-  {
-    // Close and re-open the codec (presumably to flush the queue).
-    // Actually, this causes the stream to fail in certain video
-    // files, and doesn't seem to have any useful benefit.  So screw
-    // it, and don't do this.
 
-    /*
-    avcodec_close(_video_ctx);
-    AVCodec *pVideoCodec = avcodec_find_decoder(_video_ctx->codec_id);
-    if (pVideoCodec == 0) {
-      cleanup();
-      return;
-    }
+    fetch_packet(0);
+    fetch_frame(-1);
 
-    if (avcodec_open(_video_ctx, pVideoCodec)<0) {
-      cleanup();
-      return;
+  } else {
+    // If seeking isn't supported, close-and-reopen.
+    if (backward) {
+      reset_stream();
     }
-    */
   }
-
-  fetch_packet(0);
-  fetch_frame(-1);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1065,7 +1064,6 @@ reset_stream() {
   }
 
   fetch_packet(0);
-  _initial_dts = _packet0->dts;
   fetch_frame(-1);
 }