Panda3D
|
00001 // Filename: ffmpegVideoCursor.cxx 00002 // Created by: jyelon (01Aug2007) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "ffmpegVideoCursor.h" 00016 00017 #ifdef HAVE_FFMPEG 00018 00019 #include "config_movies.h" 00020 #include "pStatCollector.h" 00021 #include "pStatTimer.h" 00022 #include "mutexHolder.h" 00023 #include "reMutexHolder.h" 00024 #include "ffmpegVideo.h" 00025 #include "bamReader.h" 00026 extern "C" { 00027 #include "libavcodec/avcodec.h" 00028 #include "libavformat/avformat.h" 00029 #ifdef HAVE_SWSCALE 00030 #include "libswscale/swscale.h" 00031 #endif 00032 } 00033 00034 ReMutex FfmpegVideoCursor::_av_lock; 00035 TypeHandle FfmpegVideoCursor::_type_handle; 00036 TypeHandle FfmpegVideoCursor::FfmpegBuffer::_type_handle; 00037 00038 PStatCollector FfmpegVideoCursor::_fetch_buffer_pcollector("*:FFMPEG Video Decoding:Fetch"); 00039 PStatCollector FfmpegVideoCursor::_seek_pcollector("*:FFMPEG Video Decoding:Seek"); 00040 PStatCollector FfmpegVideoCursor::_export_frame_pcollector("*:FFMPEG Convert Video to BGR"); 00041 00042 00043 #if LIBAVFORMAT_VERSION_MAJOR < 53 00044 #define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO 00045 #endif 00046 00047 //////////////////////////////////////////////////////////////////// 00048 // Function: FfmpegVideoCursor::Default Constructor 00049 // Access: Private 00050 // Description: This constructor is only used when reading from a bam 00051 // file. 00052 //////////////////////////////////////////////////////////////////// 00053 FfmpegVideoCursor:: 00054 FfmpegVideoCursor() : 00055 _max_readahead_frames(0), 00056 _thread_priority(ffmpeg_thread_priority), 00057 _lock("FfmpegVideoCursor::_lock"), 00058 _action_cvar(_lock), 00059 _thread_status(TS_stopped), 00060 _seek_frame(0), 00061 _packet(NULL), 00062 _format_ctx(NULL), 00063 _video_ctx(NULL), 00064 _convert_ctx(NULL), 00065 _video_index(-1), 00066 _frame(NULL), 00067 _frame_out(NULL), 00068 _eof_known(false) 00069 { 00070 } 00071 00072 //////////////////////////////////////////////////////////////////// 00073 // Function: FfmpegVideoCursor::init_from 00074 // Access: Private 00075 // Description: Specifies the source of the video cursor. This is 00076 // normally called only by the constructor or when 00077 // reading from a bam file. 00078 //////////////////////////////////////////////////////////////////// 00079 void FfmpegVideoCursor:: 00080 init_from(FfmpegVideo *source) { 00081 nassertv(_thread == NULL && _thread_status == TS_stopped); 00082 nassertv(source != NULL); 00083 _source = source; 00084 _filename = _source->get_filename(); 00085 00086 if (!open_stream()) { 00087 cleanup(); 00088 return; 00089 } 00090 00091 ReMutexHolder av_holder(_av_lock); 00092 00093 #ifdef HAVE_SWSCALE 00094 nassertv(_convert_ctx == NULL); 00095 _convert_ctx = sws_getContext(_size_x, _size_y, 00096 _video_ctx->pix_fmt, _size_x, _size_y, 00097 PIX_FMT_BGR24, SWS_BILINEAR | SWS_PRINT_INFO, NULL, NULL, NULL); 00098 #endif // HAVE_SWSCALE 00099 00100 _frame = avcodec_alloc_frame(); 00101 _frame_out = avcodec_alloc_frame(); 00102 00103 if ((_frame == 0)||(_frame_out == 0)) { 00104 cleanup(); 00105 return; 00106 } 00107 00108 _packet = new AVPacket; 00109 memset(_packet, 0, sizeof(AVPacket)); 00110 00111 fetch_packet(0); 00112 fetch_frame(-1); 00113 _initial_dts = _begin_frame; 00114 00115 _current_frame = -1; 00116 _eof_known = false; 00117 _eof_frame = 0; 00118 00119 #ifdef HAVE_THREADS 00120 set_max_readahead_frames(ffmpeg_max_readahead_frames); 00121 #endif // HAVE_THREADS 00122 } 00123 00124 //////////////////////////////////////////////////////////////////// 00125 // Function: FfmpegVideoCursor::Constructor 00126 // Access: Published 00127 // Description: 00128 //////////////////////////////////////////////////////////////////// 00129 FfmpegVideoCursor:: 00130 FfmpegVideoCursor(FfmpegVideo *src) : 00131 _max_readahead_frames(0), 00132 _thread_priority(ffmpeg_thread_priority), 00133 _lock("FfmpegVideoCursor::_lock"), 00134 _action_cvar(_lock), 00135 _thread_status(TS_stopped), 00136 _seek_frame(0), 00137 _packet(NULL), 00138 _format_ctx(NULL), 00139 _video_ctx(NULL), 00140 _convert_ctx(NULL), 00141 _video_index(-1), 00142 _frame(NULL), 00143 _frame_out(NULL), 00144 _eof_known(false) 00145 { 00146 init_from(src); 00147 } 00148 00149 //////////////////////////////////////////////////////////////////// 00150 // Function: FfmpegVideoCursor::Destructor 00151 // Access: Published 00152 // Description: 00153 //////////////////////////////////////////////////////////////////// 00154 FfmpegVideoCursor:: 00155 ~FfmpegVideoCursor() { 00156 cleanup(); 00157 } 00158 00159 //////////////////////////////////////////////////////////////////// 00160 // Function: FfmpegVideoCursor::set_max_readahead_frames 00161 // Access: Published 00162 // Description: Specifies the maximum number of frames that a 00163 // sub-thread will attempt to read ahead of the current 00164 // frame. Setting this to a nonzero allows the video 00165 // decoding to take place in a sub-thread, which 00166 // smoothes out the video decoding time by spreading it 00167 // evenly over several frames. Set this number larger 00168 // to increase the buffer between the currently visible 00169 // frame and the first undecoded frame; set it smaller 00170 // to reduce memory consumption. 00171 // 00172 // Setting this to zero forces the video to be decoded 00173 // in the main thread. If threading is not available in 00174 // the Panda build, this value is always zero. 00175 //////////////////////////////////////////////////////////////////// 00176 void FfmpegVideoCursor:: 00177 set_max_readahead_frames(int max_readahead_frames) { 00178 #ifndef HAVE_THREADS 00179 if (max_readahead_frames > 0) { 00180 ffmpeg_cat.warning() 00181 << "Couldn't set max_readahead_frames to " << max_readahead_frames 00182 << ": threading not available.\n"; 00183 max_readahead_frames = 0; 00184 } 00185 #endif // HAVE_THREADS 00186 00187 _max_readahead_frames = max_readahead_frames; 00188 if (_max_readahead_frames > 0) { 00189 if (_thread_status == TS_stopped) { 00190 start_thread(); 00191 } 00192 } else { 00193 if (_thread_status != TS_stopped) { 00194 stop_thread(); 00195 } 00196 } 00197 } 00198 00199 //////////////////////////////////////////////////////////////////// 00200 // Function: FfmpegVideoCursor::get_max_readahead_frames 00201 // Access: Published 00202 // Description: Returns the maximum number of frames that a 00203 // sub-thread will attempt to read ahead of the current 00204 // frame. See set_max_readahead_frames(). 00205 //////////////////////////////////////////////////////////////////// 00206 int FfmpegVideoCursor:: 00207 get_max_readahead_frames() const { 00208 return _max_readahead_frames; 00209 } 00210 00211 //////////////////////////////////////////////////////////////////// 00212 // Function: FfmpegVideoCursor::set_thread_priority 00213 // Access: Published 00214 // Description: Changes the thread priority of the thread that 00215 // decodes the ffmpeg video stream (if 00216 // max_readahead_frames is nonzero). Normally you 00217 // shouldn't mess with this, but there may be special 00218 // cases where a precise balance of CPU utilization 00219 // between the main thread and the various ffmpeg 00220 // service threads may be needed. 00221 //////////////////////////////////////////////////////////////////// 00222 void FfmpegVideoCursor:: 00223 set_thread_priority(ThreadPriority thread_priority) { 00224 if (_thread_priority != thread_priority) { 00225 _thread_priority = thread_priority; 00226 if (is_thread_started()) { 00227 stop_thread(); 00228 start_thread(); 00229 } 00230 } 00231 } 00232 00233 //////////////////////////////////////////////////////////////////// 00234 // Function: FfmpegVideoCursor::get_thread_priority 00235 // Access: Published 00236 // Description: Returns the current thread priority of the thread that 00237 // decodes the ffmpeg video stream (if 00238 // max_readahead_frames is nonzero). See 00239 // set_thread_priority(). 00240 //////////////////////////////////////////////////////////////////// 00241 ThreadPriority FfmpegVideoCursor:: 00242 get_thread_priority() const { 00243 return _thread_priority; 00244 } 00245 00246 //////////////////////////////////////////////////////////////////// 00247 // Function: FfmpegVideoCursor::start_thread 00248 // Access: Published 00249 // Description: Explicitly starts the ffmpeg decoding thread after it 00250 // has been stopped by a call to stop_thread(). The 00251 // thread is normally started automatically, so there is 00252 // no need to call this method unless you have 00253 // previously called stop_thread() for some reason. 00254 //////////////////////////////////////////////////////////////////// 00255 void FfmpegVideoCursor:: 00256 start_thread() { 00257 MutexHolder holder(_lock); 00258 00259 if (_thread_status == TS_stopped && _max_readahead_frames > 0) { 00260 // Get a unique name for the thread's sync name. 00261 ostringstream strm; 00262 strm << (void *)this; 00263 _sync_name = strm.str(); 00264 00265 // Create and start the thread object. 00266 _thread_status = TS_wait; 00267 _thread = new GenericThread(_filename.get_basename(), _sync_name, st_thread_main, this); 00268 if (!_thread->start(_thread_priority, true)) { 00269 // Couldn't start the thread. 00270 _thread = NULL; 00271 _thread_status = TS_stopped; 00272 } 00273 } 00274 } 00275 00276 //////////////////////////////////////////////////////////////////// 00277 // Function: FfmpegVideoCursor::stop_thread 00278 // Access: Published 00279 // Description: Explicitly stops the ffmpeg decoding thread. There 00280 // is normally no reason to do this unless you want to 00281 // maintain precise control over what threads are 00282 // consuming CPU resources. Calling this method will 00283 // make the video update in the main thread, regardless 00284 // of the setting of max_readahead_frames, until you 00285 // call start_thread() again. 00286 //////////////////////////////////////////////////////////////////// 00287 void FfmpegVideoCursor:: 00288 stop_thread() { 00289 if (_thread_status != TS_stopped) { 00290 PT(GenericThread) thread = _thread; 00291 { 00292 MutexHolder holder(_lock); 00293 if (_thread_status != TS_stopped) { 00294 _thread_status = TS_shutdown; 00295 } 00296 _action_cvar.notify(); 00297 _thread = NULL; 00298 } 00299 00300 // Now that we've released the lock, we can join the thread. 00301 thread->join(); 00302 } 00303 00304 // This is a good time to clean up all of the allocated frame 00305 // objects. It's not really necessary to be holding the lock, since 00306 // the thread is gone, but we'll grab it anyway just in case someone 00307 // else starts the thread up again. 00308 MutexHolder holder(_lock); 00309 00310 _readahead_frames.clear(); 00311 } 00312 00313 //////////////////////////////////////////////////////////////////// 00314 // Function: FfmpegVideoCursor::is_thread_started 00315 // Access: Published 00316 // Description: Returns true if the thread has been started, false if 00317 // not. This will always return false if 00318 // max_readahead_frames is 0. 00319 //////////////////////////////////////////////////////////////////// 00320 bool FfmpegVideoCursor:: 00321 is_thread_started() const { 00322 return (_thread_status != TS_stopped); 00323 } 00324 00325 //////////////////////////////////////////////////////////////////// 00326 // Function: FfmpegVideoCursor::set_time 00327 // Access: Published, Virtual 00328 // Description: See MovieVideoCursor::set_time(). 00329 //////////////////////////////////////////////////////////////////// 00330 bool FfmpegVideoCursor:: 00331 set_time(double timestamp, int loop_count) { 00332 int frame = (int)(timestamp / _video_timebase + 0.5); 00333 00334 if (_eof_known) { 00335 if (loop_count == 0) { 00336 frame = frame % _eof_frame; 00337 } else { 00338 int last_frame = _eof_frame * loop_count; 00339 if (frame < last_frame) { 00340 frame = frame % _eof_frame; 00341 } else { 00342 frame = _eof_frame - 1; 00343 } 00344 } 00345 } 00346 00347 // No point in trying to position before the first frame. 00348 frame = max(frame, _initial_dts); 00349 00350 if (ffmpeg_cat.is_spam() && frame != _current_frame) { 00351 ffmpeg_cat.spam() 00352 << "set_time(" << timestamp << "): " << frame 00353 << ", loop_count = " << loop_count << "\n"; 00354 } 00355 00356 _current_frame = frame; 00357 if (_current_frame_buffer != NULL) { 00358 // If we've previously returned a frame, don't bother asking for a 00359 // next one if that frame is still valid. 00360 return (_current_frame >= _current_frame_buffer->_end_frame || 00361 _current_frame < _current_frame_buffer->_begin_frame); 00362 } 00363 00364 // If our last request didn't return a frame, try again. 00365 return true; 00366 } 00367 00368 //////////////////////////////////////////////////////////////////// 00369 // Function: FfmpegVideoCursor::fetch_buffer 00370 // Access: Public, Virtual 00371 // Description: See MovieVideoCursor::fetch_buffer. 00372 //////////////////////////////////////////////////////////////////// 00373 PT(MovieVideoCursor::Buffer) FfmpegVideoCursor:: 00374 fetch_buffer() { 00375 MutexHolder holder(_lock); 00376 00377 // If there was an error at any point, just return NULL. 00378 if (_format_ctx == (AVFormatContext *)NULL) { 00379 return NULL; 00380 } 00381 00382 PT(FfmpegBuffer) frame; 00383 if (_thread_status == TS_stopped) { 00384 // Non-threaded case. Just get the next frame directly. 00385 advance_to_frame(_current_frame); 00386 if (_frame_ready) { 00387 frame = do_alloc_frame(); 00388 export_frame(frame); 00389 } 00390 00391 } else { 00392 // Threaded case. Wait for the thread to serve up the required 00393 // frames. 00394 if (!_readahead_frames.empty()) { 00395 frame = _readahead_frames.front(); 00396 _readahead_frames.pop_front(); 00397 _action_cvar.notify(); 00398 while (frame->_end_frame < _current_frame && !_readahead_frames.empty()) { 00399 // This frame is too old. Discard it. 00400 if (ffmpeg_cat.is_debug()) { 00401 ffmpeg_cat.debug() 00402 << "ffmpeg for " << _filename.get_basename() 00403 << " at frame " << _current_frame << ", discarding frame at " 00404 << frame->_begin_frame << "\n"; 00405 } 00406 frame = _readahead_frames.front(); 00407 _readahead_frames.pop_front(); 00408 } 00409 if (frame->_begin_frame > _current_frame) { 00410 // This frame is too new. Empty all remaining frames and seek 00411 // backwards. 00412 if (ffmpeg_cat.is_debug()) { 00413 ffmpeg_cat.debug() 00414 << "ffmpeg for " << _filename.get_basename() 00415 << " at frame " << _current_frame << ", encountered too-new frame at " 00416 << frame->_begin_frame << "\n"; 00417 } 00418 do_clear_all_frames(); 00419 if (_thread_status == TS_wait || _thread_status == TS_seek || _thread_status == TS_readahead) { 00420 _thread_status = TS_seek; 00421 _seek_frame = _current_frame; 00422 _action_cvar.notify(); 00423 } 00424 } 00425 } 00426 if (frame == NULL || frame->_end_frame < _current_frame) { 00427 // No frame available, or the frame is too old. Seek. 00428 if (_thread_status == TS_wait || _thread_status == TS_seek || _thread_status == TS_readahead) { 00429 _thread_status = TS_seek; 00430 _seek_frame = _current_frame; 00431 _action_cvar.notify(); 00432 } 00433 } 00434 } 00435 00436 if (frame != NULL) { 00437 bool too_old = (frame->_end_frame < _current_frame && !ffmpeg_show_seek_frames); 00438 bool too_new = frame->_begin_frame > _current_frame; 00439 if (too_old || too_new) { 00440 // The frame is too old or too new. Just recycle it. 00441 frame = NULL; 00442 } 00443 } 00444 00445 if (frame != NULL) { 00446 _current_frame_buffer = frame; 00447 if (ffmpeg_cat.is_debug()) { 00448 ffmpeg_cat.debug() 00449 << "ffmpeg for " << _filename.get_basename() 00450 << " at frame " << _current_frame << ", returning frame at " 00451 << frame->_begin_frame << "\n"; 00452 } 00453 } else { 00454 if (ffmpeg_cat.is_debug()) { 00455 ffmpeg_cat.debug() 00456 << "ffmpeg for " << _filename.get_basename() 00457 << " at frame " << _current_frame << ", returning NULL\n"; 00458 } 00459 } 00460 return frame.p(); 00461 } 00462 00463 //////////////////////////////////////////////////////////////////// 00464 // Function: FfmpegVideoCursor::make_new_buffer 00465 // Access: Protected, Virtual 00466 // Description: May be called by a derived class to allocate a new 00467 // Buffer object. 00468 //////////////////////////////////////////////////////////////////// 00469 PT(MovieVideoCursor::Buffer) FfmpegVideoCursor:: 00470 make_new_buffer() { 00471 PT(FfmpegBuffer) frame = new FfmpegBuffer(size_x() * size_y() * get_num_components(), _video_timebase); 00472 return frame.p(); 00473 } 00474 00475 //////////////////////////////////////////////////////////////////// 00476 // Function: FfmpegVideoCursor::open_stream 00477 // Access: Private 00478 // Description: Opens the stream for the first time, or when needed 00479 // internally. 00480 //////////////////////////////////////////////////////////////////// 00481 bool FfmpegVideoCursor:: 00482 open_stream() { 00483 nassertr(!_ffvfile.is_open(), false); 00484 00485 // Hold the global lock while we open the file and create avcodec 00486 // objects. 00487 ReMutexHolder av_holder(_av_lock); 00488 00489 if (!_source->get_subfile_info().is_empty()) { 00490 // Read a subfile. 00491 if (!_ffvfile.open_subfile(_source->get_subfile_info())) { 00492 ffmpeg_cat.info() 00493 << "Couldn't open " << _source->get_subfile_info() << "\n"; 00494 close_stream(); 00495 return false; 00496 } 00497 00498 } else { 00499 // Read a filename. 00500 if (!_ffvfile.open_vfs(_filename)) { 00501 ffmpeg_cat.info() 00502 << "Couldn't open " << _filename << "\n"; 00503 close_stream(); 00504 return false; 00505 } 00506 } 00507 00508 nassertr(_format_ctx == NULL, false); 00509 _format_ctx = _ffvfile.get_format_context(); 00510 nassertr(_format_ctx != NULL, false); 00511 00512 if (av_find_stream_info(_format_ctx) < 0) { 00513 ffmpeg_cat.info() 00514 << "Couldn't find stream info\n"; 00515 close_stream(); 00516 return false; 00517 } 00518 00519 // Find the video stream 00520 nassertr(_video_ctx == NULL, false); 00521 for (int i = 0; i < (int)_format_ctx->nb_streams; ++i) { 00522 if (_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { 00523 _video_index = i; 00524 _video_ctx = _format_ctx->streams[i]->codec; 00525 _video_timebase = av_q2d(_format_ctx->streams[i]->time_base); 00526 _min_fseek = (int)(3.0 / _video_timebase); 00527 } 00528 } 00529 00530 if (_video_ctx == NULL) { 00531 ffmpeg_cat.info() 00532 << "Couldn't find video_ctx\n"; 00533 close_stream(); 00534 return false; 00535 } 00536 00537 AVCodec *pVideoCodec = avcodec_find_decoder(_video_ctx->codec_id); 00538 if (pVideoCodec == NULL) { 00539 ffmpeg_cat.info() 00540 << "Couldn't find codec\n"; 00541 close_stream(); 00542 return false; 00543 } 00544 if (avcodec_open(_video_ctx, pVideoCodec) < 0) { 00545 ffmpeg_cat.info() 00546 << "Couldn't open codec\n"; 00547 close_stream(); 00548 return false; 00549 } 00550 00551 _size_x = _video_ctx->width; 00552 _size_y = _video_ctx->height; 00553 _num_components = 3; // Don't know how to implement RGBA movies yet. 00554 _length = (double)_format_ctx->duration / (double)AV_TIME_BASE; 00555 _can_seek = true; 00556 _can_seek_fast = true; 00557 00558 return true; 00559 } 00560 00561 //////////////////////////////////////////////////////////////////// 00562 // Function: FfmpegVideoCursor::close_stream 00563 // Access: Private 00564 // Description: Closes the stream, during cleanup or when needed 00565 // internally. 00566 //////////////////////////////////////////////////////////////////// 00567 void FfmpegVideoCursor:: 00568 close_stream() { 00569 // Hold the global lock while we free avcodec objects. 00570 ReMutexHolder av_holder(_av_lock); 00571 00572 if ((_video_ctx)&&(_video_ctx->codec)) { 00573 avcodec_close(_video_ctx); 00574 } 00575 _video_ctx = NULL; 00576 00577 _ffvfile.close(); 00578 _format_ctx = NULL; 00579 00580 _video_index = -1; 00581 } 00582 00583 //////////////////////////////////////////////////////////////////// 00584 // Function: FfmpegVideoCursor::cleanup 00585 // Access: Private 00586 // Description: Reset to a standard inactive state. 00587 //////////////////////////////////////////////////////////////////// 00588 void FfmpegVideoCursor:: 00589 cleanup() { 00590 stop_thread(); 00591 close_stream(); 00592 00593 ReMutexHolder av_holder(_av_lock); 00594 00595 #ifdef HAVE_SWSCALE 00596 if (_convert_ctx != NULL) { 00597 sws_freeContext(_convert_ctx); 00598 } 00599 _convert_ctx = NULL; 00600 #endif // HAVE_SWSCALE 00601 00602 if (_frame) { 00603 av_free(_frame); 00604 _frame = NULL; 00605 } 00606 00607 if (_frame_out) { 00608 _frame_out->data[0] = 0; 00609 av_free(_frame_out); 00610 _frame_out = NULL; 00611 } 00612 00613 if (_packet) { 00614 if (_packet->data) { 00615 av_free_packet(_packet); 00616 } 00617 delete _packet; 00618 _packet = NULL; 00619 } 00620 } 00621 00622 //////////////////////////////////////////////////////////////////// 00623 // Function: FfmpegVideoCursor::st_thread_main 00624 // Access: Private, Static 00625 // Description: The thread main function, static version (for passing 00626 // to GenericThread). 00627 //////////////////////////////////////////////////////////////////// 00628 void FfmpegVideoCursor:: 00629 st_thread_main(void *self) { 00630 ((FfmpegVideoCursor *)self)->thread_main(); 00631 } 00632 00633 //////////////////////////////////////////////////////////////////// 00634 // Function: FfmpegVideoCursor::thread_main 00635 // Access: Private 00636 // Description: The thread main function. 00637 //////////////////////////////////////////////////////////////////// 00638 void FfmpegVideoCursor:: 00639 thread_main() { 00640 if (ffmpeg_cat.is_spam()) { 00641 ffmpeg_cat.spam() 00642 << "ffmpeg thread for " << _filename.get_basename() << " starting.\n"; 00643 } 00644 00645 // First, push the first frame onto the readahead queue. 00646 if (_frame_ready) { 00647 PT(FfmpegBuffer) frame = do_alloc_frame(); 00648 export_frame(frame); 00649 MutexHolder holder(_lock); 00650 _readahead_frames.push_back(frame); 00651 } 00652 00653 // Now repeatedly wait for something interesting to do, until we're told 00654 // to shut down. 00655 MutexHolder holder(_lock); 00656 while (_thread_status != TS_shutdown) { 00657 nassertv(_thread_status != TS_stopped); 00658 _action_cvar.wait(); 00659 00660 while (do_poll()) { 00661 // Keep doing stuff as long as there's something to do. 00662 _lock.release(); 00663 PStatClient::thread_tick(_sync_name); 00664 Thread::consider_yield(); 00665 _lock.acquire(); 00666 } 00667 } 00668 00669 _thread_status = TS_stopped; 00670 if (ffmpeg_cat.is_spam()) { 00671 ffmpeg_cat.spam() 00672 << "ffmpeg thread for " << _filename.get_basename() << " stopped.\n"; 00673 } 00674 } 00675 00676 //////////////////////////////////////////////////////////////////// 00677 // Function: FfmpegVideoCursor::do_poll 00678 // Access: Private 00679 // Description: Called within the sub-thread. Assumes the lock is 00680 // already held. If there is something for the thread 00681 // to do, does it and returns true. If there is nothing 00682 // for the thread to do, returns false. 00683 //////////////////////////////////////////////////////////////////// 00684 bool FfmpegVideoCursor:: 00685 do_poll() { 00686 switch (_thread_status) { 00687 case TS_stopped: 00688 case TS_seeking: 00689 // This shouldn't be possible while the thread is running. 00690 nassertr(false, false); 00691 return false; 00692 00693 case TS_wait: 00694 // The video hasn't started playing yet. 00695 return false; 00696 00697 case TS_readahead: 00698 if ((int)_readahead_frames.size() < _max_readahead_frames) { 00699 // Time to read the next frame. 00700 PT(FfmpegBuffer) frame = do_alloc_frame(); 00701 nassertr(frame != NULL, false); 00702 _lock.release(); 00703 fetch_frame(-1); 00704 if (_frame_ready) { 00705 export_frame(frame); 00706 _lock.acquire(); 00707 _readahead_frames.push_back(frame); 00708 } else { 00709 // No frame. 00710 _lock.acquire(); 00711 } 00712 return true; 00713 } 00714 00715 // No room for the next frame yet. Wait for more. 00716 return false; 00717 00718 case TS_seek: 00719 // Seek to a specific frame. 00720 { 00721 int seek_frame = _seek_frame; 00722 _thread_status = TS_seeking; 00723 PT(FfmpegBuffer) frame = do_alloc_frame(); 00724 nassertr(frame != NULL, false); 00725 _lock.release(); 00726 advance_to_frame(seek_frame); 00727 if (_frame_ready) { 00728 export_frame(frame); 00729 _lock.acquire(); 00730 do_clear_all_frames(); 00731 _readahead_frames.push_back(frame); 00732 } else { 00733 _lock.acquire(); 00734 do_clear_all_frames(); 00735 } 00736 00737 if (_thread_status == TS_seeking) { 00738 // After seeking, we automatically transition to readahead. 00739 _thread_status = TS_readahead; 00740 } 00741 } 00742 return true; 00743 00744 case TS_shutdown: 00745 // Time to stop the thread. 00746 return false; 00747 } 00748 00749 return false; 00750 } 00751 00752 //////////////////////////////////////////////////////////////////// 00753 // Function: FfmpegVideoCursor::do_alloc_frame 00754 // Access: Private 00755 // Description: Allocates a new Buffer object. Assumes the lock is 00756 // held. 00757 //////////////////////////////////////////////////////////////////// 00758 PT(FfmpegVideoCursor::FfmpegBuffer) FfmpegVideoCursor:: 00759 do_alloc_frame() { 00760 PT(Buffer) buffer = make_new_buffer(); 00761 return (FfmpegBuffer *)buffer.p(); 00762 } 00763 00764 //////////////////////////////////////////////////////////////////// 00765 // Function: FfmpegVideoCursor::do_clear_all_frames 00766 // Access: Private 00767 // Description: Empties the entire readahead_frames queue. 00768 // Assumes the lock is held. 00769 //////////////////////////////////////////////////////////////////// 00770 void FfmpegVideoCursor:: 00771 do_clear_all_frames() { 00772 _readahead_frames.clear(); 00773 } 00774 00775 //////////////////////////////////////////////////////////////////// 00776 // Function: FfmpegVideoCursor::fetch_packet 00777 // Access: Private 00778 // Description: Called within the sub-thread. Fetches a video packet 00779 // and stores it in the packet0 buffer. Sets packet_frame 00780 // to the packet's timestamp. If a packet could not be 00781 // read, the packet is cleared and the packet_frame is 00782 // set to the specified default value. Returns true on 00783 // failure (such as the end of the video), or false on 00784 // success. 00785 //////////////////////////////////////////////////////////////////// 00786 bool FfmpegVideoCursor:: 00787 fetch_packet(int default_frame) { 00788 if (ffmpeg_global_lock) { 00789 ReMutexHolder av_holder(_av_lock); 00790 return do_fetch_packet(default_frame); 00791 } else { 00792 return do_fetch_packet(default_frame); 00793 } 00794 } 00795 00796 //////////////////////////////////////////////////////////////////// 00797 // Function: FfmpegVideoCursor::do_fetch_packet 00798 // Access: Private 00799 // Description: As above, with the ffmpeg global lock held (if 00800 // configured on). 00801 //////////////////////////////////////////////////////////////////// 00802 bool FfmpegVideoCursor:: 00803 do_fetch_packet(int default_frame) { 00804 if (_packet->data) { 00805 av_free_packet(_packet); 00806 } 00807 while (av_read_frame(_format_ctx, _packet) >= 0) { 00808 if (_packet->stream_index == _video_index) { 00809 _packet_frame = _packet->dts; 00810 return false; 00811 } 00812 av_free_packet(_packet); 00813 } 00814 _packet->data = 0; 00815 00816 if (!_eof_known && default_frame != 0) { 00817 _eof_frame = _packet_frame; 00818 _eof_known = true; 00819 } 00820 00821 if (ffmpeg_cat.is_spam()) { 00822 if (_eof_known) { 00823 ffmpeg_cat.spam() 00824 << "end of video at frame " << _eof_frame << "\n"; 00825 } else { 00826 ffmpeg_cat.spam() 00827 << "end of video\n"; 00828 } 00829 } 00830 _packet_frame = default_frame; 00831 return true; 00832 } 00833 00834 //////////////////////////////////////////////////////////////////// 00835 // Function: FfmpegVideoCursor::fetch_frame 00836 // Access: Private 00837 // Description: Called within the sub-thread. Slides forward until 00838 // the indicated frame, then fetches a frame from the 00839 // stream and stores it in the frame buffer. Sets 00840 // _begin_frame and _end_frame to indicate the extents of 00841 // the frame. Sets _frame_ready true to indicate a 00842 // frame is now available, or false if it is not (for 00843 // instance, because the end of the video was reached). 00844 //////////////////////////////////////////////////////////////////// 00845 void FfmpegVideoCursor:: 00846 fetch_frame(int frame) { 00847 PStatTimer timer(_fetch_buffer_pcollector); 00848 00849 int finished = 0; 00850 00851 if (_packet_frame <= frame) { 00852 finished = 0; 00853 00854 // Get the next packet. The first packet beyond the frame we're 00855 // looking for marks the point to stop. 00856 while (_packet_frame <= frame) { 00857 PStatTimer timer(_seek_pcollector); 00858 00859 // Decode the previous packet, and get the next one. 00860 decode_frame(finished); 00861 _begin_frame = _packet_frame; 00862 if (fetch_packet(frame)) { 00863 _end_frame = _packet_frame; 00864 _frame_ready = false; 00865 return; 00866 } 00867 } 00868 00869 } else { 00870 // Just get the next frame. 00871 finished = 0; 00872 while (!finished && _packet->data) { 00873 decode_frame(finished); 00874 _begin_frame = _packet_frame; 00875 fetch_packet(_begin_frame + 1); 00876 } 00877 } 00878 00879 _end_frame = _packet_frame; 00880 _frame_ready = true; 00881 } 00882 00883 //////////////////////////////////////////////////////////////////// 00884 // Function: FfmpegVideoCursor::decode_frame 00885 // Access: Private 00886 // Description: Called within the sub-thread. Decodes the data in 00887 // the specified packet into _frame. 00888 //////////////////////////////////////////////////////////////////// 00889 void FfmpegVideoCursor:: 00890 decode_frame(int &finished) { 00891 if (ffmpeg_global_lock) { 00892 ReMutexHolder av_holder(_av_lock); 00893 do_decode_frame(finished); 00894 } else { 00895 do_decode_frame(finished); 00896 } 00897 } 00898 00899 //////////////////////////////////////////////////////////////////// 00900 // Function: FfmpegVideoCursor::do_decode_frame 00901 // Access: Private 00902 // Description: As above, with the ffmpeg global lock held (if 00903 // configured on). 00904 //////////////////////////////////////////////////////////////////// 00905 void FfmpegVideoCursor:: 00906 do_decode_frame(int &finished) { 00907 #if LIBAVCODEC_VERSION_INT < 3414272 00908 avcodec_decode_video(_video_ctx, _frame, 00909 &finished, _packet->data, _packet->size); 00910 #else 00911 avcodec_decode_video2(_video_ctx, _frame, &finished, _packet); 00912 #endif 00913 } 00914 00915 //////////////////////////////////////////////////////////////////// 00916 // Function: FfmpegVideoCursor::seek 00917 // Access: Private 00918 // Description: Called within the sub-thread. Seeks to a target 00919 // location. Afterward, the packet_frame is guaranteed 00920 // to be less than or equal to the specified frame. 00921 //////////////////////////////////////////////////////////////////// 00922 void FfmpegVideoCursor:: 00923 seek(int frame, bool backward) { 00924 PStatTimer timer(_seek_pcollector); 00925 00926 if (ffmpeg_support_seek) { 00927 if (ffmpeg_global_lock) { 00928 ReMutexHolder av_holder(_av_lock); 00929 do_seek(frame, backward); 00930 } else { 00931 do_seek(frame, backward); 00932 } 00933 00934 } else { 00935 // If seeking isn't supported, close-and-reopen. 00936 if (backward) { 00937 reset_stream(); 00938 } 00939 } 00940 } 00941 00942 //////////////////////////////////////////////////////////////////// 00943 // Function: FfmpegVideoCursor::do_seek 00944 // Access: Private 00945 // Description: As above, with the ffmpeg global lock held (if 00946 // configured on). Also only if ffmpeg-support-seek is 00947 // on. 00948 //////////////////////////////////////////////////////////////////// 00949 void FfmpegVideoCursor:: 00950 do_seek(int frame, bool backward) { 00951 PN_int64 target_ts = (PN_int64)frame; 00952 if (target_ts < (PN_int64)(_initial_dts)) { 00953 // Attempts to seek before the first packet will fail. 00954 target_ts = _initial_dts; 00955 } 00956 int flags = 0; 00957 if (backward) { 00958 flags = AVSEEK_FLAG_BACKWARD; 00959 } 00960 00961 if (av_seek_frame(_format_ctx, _video_index, target_ts, flags) < 0) { 00962 if (ffmpeg_cat.is_spam()) { 00963 ffmpeg_cat.spam() 00964 << "Seek failure.\n"; 00965 } 00966 00967 if (backward) { 00968 // Now try to seek forward. 00969 reset_stream(); 00970 seek(frame, false); 00971 return; 00972 } 00973 00974 // Try a binary search to get a little closer. 00975 if (binary_seek(_initial_dts, frame, frame, 1) < 0) { 00976 if (ffmpeg_cat.is_spam()) { 00977 ffmpeg_cat.spam() 00978 << "Seek double failure.\n"; 00979 } 00980 reset_stream(); 00981 return; 00982 } 00983 } 00984 00985 fetch_packet(0); 00986 fetch_frame(-1); 00987 } 00988 00989 //////////////////////////////////////////////////////////////////// 00990 // Function: FfmpegVideoCursor::binary_seek 00991 // Access: Private 00992 // Description: Casts about within the stream for a reasonably-close 00993 // frame to seek to. We're trying to get as close as 00994 // possible to target_frame. 00995 //////////////////////////////////////////////////////////////////// 00996 int FfmpegVideoCursor:: 00997 binary_seek(int min_frame, int max_frame, int target_frame, int num_iterations) { 00998 int try_frame = (min_frame + max_frame) / 2; 00999 if (num_iterations > 5 || try_frame >= max_frame) { 01000 // Success. 01001 return 0; 01002 } 01003 01004 if (av_seek_frame(_format_ctx, _video_index, try_frame, AVSEEK_FLAG_BACKWARD) < 0) { 01005 // Failure. Try lower. 01006 if (binary_seek(min_frame, try_frame - 1, target_frame, num_iterations + 1) < 0) { 01007 return -1; 01008 } 01009 } else { 01010 // Success. Try higher. 01011 if (binary_seek(try_frame + 1, max_frame, target_frame, num_iterations + 1) < 0) { 01012 return -1; 01013 } 01014 } 01015 return 0; 01016 } 01017 01018 //////////////////////////////////////////////////////////////////// 01019 // Function: FfmpegVideoCursor::reset_stream 01020 // Access: Private 01021 // Description: Resets the stream to its initial, first-opened state 01022 // by closing and re-opening it. 01023 //////////////////////////////////////////////////////////////////// 01024 void FfmpegVideoCursor:: 01025 reset_stream() { 01026 if (ffmpeg_cat.is_spam()) { 01027 ffmpeg_cat.spam() 01028 << "Resetting ffmpeg stream.\n"; 01029 } 01030 01031 close_stream(); 01032 if (!open_stream()) { 01033 ffmpeg_cat.error() 01034 << "Stream error, invalidating movie.\n"; 01035 cleanup(); 01036 return; 01037 } 01038 01039 fetch_packet(0); 01040 fetch_frame(-1); 01041 } 01042 01043 //////////////////////////////////////////////////////////////////// 01044 // Function: FfmpegVideoCursor::advance_to_frame 01045 // Access: Private 01046 // Description: Called within the sub-thread. Advance until the 01047 // specified frame is in the export buffer. 01048 //////////////////////////////////////////////////////////////////// 01049 void FfmpegVideoCursor:: 01050 advance_to_frame(int frame) { 01051 PStatTimer timer(_fetch_buffer_pcollector); 01052 01053 if (frame < _begin_frame) { 01054 // Frame is in the past. 01055 if (ffmpeg_cat.is_spam()) { 01056 ffmpeg_cat.spam() 01057 << "Seeking backward to " << frame << " from " << _begin_frame << "\n"; 01058 } 01059 seek(frame, true); 01060 if (_begin_frame > frame) { 01061 if (ffmpeg_cat.is_spam()) { 01062 ffmpeg_cat.spam() 01063 << "Ended up at " << _begin_frame << ", not far enough back!\n"; 01064 } 01065 reset_stream(); 01066 if (ffmpeg_cat.is_spam()) { 01067 ffmpeg_cat.spam() 01068 << "Reseek to 0, got " << _begin_frame << "\n"; 01069 } 01070 } 01071 if (frame > _end_frame) { 01072 if (ffmpeg_cat.is_spam()) { 01073 ffmpeg_cat.spam() 01074 << "Now sliding forward to " << frame << " from " << _begin_frame << "\n"; 01075 } 01076 fetch_frame(frame); 01077 } 01078 01079 } else if (frame < _end_frame) { 01080 // Frame is in the present: already have the frame. 01081 if (ffmpeg_cat.is_spam()) { 01082 ffmpeg_cat.spam() 01083 << "Currently have " << frame << " within " << _begin_frame << " .. " << _end_frame << "\n"; 01084 } 01085 01086 } else if (frame < _end_frame + _min_fseek) { 01087 // Frame is in the near future. 01088 if (ffmpeg_cat.is_spam()) { 01089 ffmpeg_cat.spam() 01090 << "Sliding forward to " << frame << " from " << _begin_frame << "\n"; 01091 } 01092 fetch_frame(frame); 01093 01094 } else { 01095 // Frame is in the far future. Seek forward, then read. 01096 // There's a danger here: because keyframes are spaced 01097 // unpredictably, trying to seek forward could actually 01098 // move us backward in the stream! This must be avoided. 01099 // So the rule is, try the seek. If it hurts us by moving 01100 // us backward, we increase the minimum threshold distance 01101 // for forward-seeking in the future. 01102 01103 if (ffmpeg_cat.is_spam()) { 01104 ffmpeg_cat.spam() 01105 << "Jumping forward to " << frame << " from " << _begin_frame << "\n"; 01106 } 01107 int base = _begin_frame; 01108 seek(frame, false); 01109 if (_begin_frame < base) { 01110 _min_fseek += (base - _begin_frame); 01111 if (ffmpeg_cat.is_spam()) { 01112 ffmpeg_cat.spam() 01113 << "Wrong way! Increasing _min_fseek to " << _min_fseek << "\n"; 01114 } 01115 } 01116 if (frame > _end_frame) { 01117 if (ffmpeg_cat.is_spam()) { 01118 ffmpeg_cat.spam() 01119 << "Correcting, sliding forward to " << frame << " from " << _begin_frame << "\n"; 01120 } 01121 fetch_frame(frame); 01122 } 01123 } 01124 01125 if (ffmpeg_cat.is_spam()) { 01126 ffmpeg_cat.spam() 01127 << "Wanted " << frame << ", got " << _begin_frame << "\n"; 01128 } 01129 } 01130 01131 //////////////////////////////////////////////////////////////////// 01132 // Function: FfmpegVideoCursor::export_frame 01133 // Access: Private 01134 // Description: Called within the sub-thread. Exports the contents 01135 // of the frame buffer into the indicated target buffer. 01136 //////////////////////////////////////////////////////////////////// 01137 void FfmpegVideoCursor:: 01138 export_frame(FfmpegBuffer *buffer) { 01139 PStatTimer timer(_export_frame_pcollector); 01140 01141 if (!_frame_ready) { 01142 // No frame data ready, just fill with black. 01143 if (ffmpeg_cat.is_spam()) { 01144 ffmpeg_cat.spam() 01145 << "ffmpeg for " << _filename.get_basename() 01146 << ", no frame available.\n"; 01147 } 01148 memset(buffer->_block, 0, buffer->_block_size); 01149 return; 01150 } 01151 01152 _frame_out->data[0] = buffer->_block + ((_size_y - 1) * _size_x * 3); 01153 _frame_out->linesize[0] = _size_x * -3; 01154 buffer->_begin_frame = _begin_frame; 01155 buffer->_end_frame = _end_frame; 01156 01157 if (ffmpeg_global_lock) { 01158 ReMutexHolder av_holder(_av_lock); 01159 #ifdef HAVE_SWSCALE 01160 nassertv(_convert_ctx != NULL && _frame != NULL && _frame_out != NULL); 01161 sws_scale(_convert_ctx, _frame->data, _frame->linesize, 0, _size_y, _frame_out->data, _frame_out->linesize); 01162 #else 01163 img_convert((AVPicture *)_frame_out, PIX_FMT_BGR24, 01164 (AVPicture *)_frame, _video_ctx->pix_fmt, _size_x, _size_y); 01165 #endif 01166 } else { 01167 #ifdef HAVE_SWSCALE 01168 nassertv(_convert_ctx != NULL && _frame != NULL && _frame_out != NULL); 01169 sws_scale(_convert_ctx, _frame->data, _frame->linesize, 0, _size_y, _frame_out->data, _frame_out->linesize); 01170 #else 01171 img_convert((AVPicture *)_frame_out, PIX_FMT_BGR24, 01172 (AVPicture *)_frame, _video_ctx->pix_fmt, _size_x, _size_y); 01173 #endif 01174 } 01175 } 01176 01177 //////////////////////////////////////////////////////////////////// 01178 // Function: FfmpegVideoCursor::register_with_read_factory 01179 // Access: Public, Static 01180 // Description: Tells the BamReader how to create objects of type 01181 // FfmpegVideo. 01182 //////////////////////////////////////////////////////////////////// 01183 void FfmpegVideoCursor:: 01184 register_with_read_factory() { 01185 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 01186 } 01187 01188 //////////////////////////////////////////////////////////////////// 01189 // Function: FfmpegVideoCursor::write_datagram 01190 // Access: Public, Virtual 01191 // Description: Writes the contents of this object to the datagram 01192 // for shipping out to a Bam file. 01193 //////////////////////////////////////////////////////////////////// 01194 void FfmpegVideoCursor:: 01195 write_datagram(BamWriter *manager, Datagram &dg) { 01196 MovieVideoCursor::write_datagram(manager, dg); 01197 01198 // No need to write any additional data here--all of it comes 01199 // implicitly from the underlying MovieVideo, which we process in 01200 // finalize(). 01201 } 01202 01203 //////////////////////////////////////////////////////////////////// 01204 // Function: FfmpegVideoCursor::finalize 01205 // Access: Public, Virtual 01206 // Description: Called by the BamReader to perform any final actions 01207 // needed for setting up the object after all objects 01208 // have been read and all pointers have been completed. 01209 //////////////////////////////////////////////////////////////////// 01210 void FfmpegVideoCursor:: 01211 finalize(BamReader *) { 01212 if (_source != (MovieVideo *)NULL) { 01213 FfmpegVideo *video; 01214 DCAST_INTO_V(video, _source); 01215 init_from(video); 01216 } 01217 } 01218 01219 //////////////////////////////////////////////////////////////////// 01220 // Function: FfmpegVideoCursor::make_from_bam 01221 // Access: Private, Static 01222 // Description: This function is called by the BamReader's factory 01223 // when a new object of type FfmpegVideo is encountered 01224 // in the Bam file. It should create the FfmpegVideo 01225 // and extract its information from the file. 01226 //////////////////////////////////////////////////////////////////// 01227 TypedWritable *FfmpegVideoCursor:: 01228 make_from_bam(const FactoryParams ¶ms) { 01229 FfmpegVideoCursor *video = new FfmpegVideoCursor; 01230 DatagramIterator scan; 01231 BamReader *manager; 01232 01233 parse_params(params, scan, manager); 01234 video->fillin(scan, manager); 01235 01236 return video; 01237 } 01238 01239 //////////////////////////////////////////////////////////////////// 01240 // Function: FfmpegVideoCursor::fillin 01241 // Access: Private 01242 // Description: This internal function is called by make_from_bam to 01243 // read in all of the relevant data from the BamFile for 01244 // the new FfmpegVideo. 01245 //////////////////////////////////////////////////////////////////// 01246 void FfmpegVideoCursor:: 01247 fillin(DatagramIterator &scan, BamReader *manager) { 01248 MovieVideoCursor::fillin(scan, manager); 01249 01250 // The MovieVideoCursor gets the underlying MovieVideo pointer. We 01251 // need a finalize callback so we can initialize ourselves once that 01252 // has been read completely. 01253 manager->register_finalize(this); 01254 } 01255 01256 //////////////////////////////////////////////////////////////////// 01257 // Function: FfmpegVideoCursor::FfmpegBuffer::compare_timestamp 01258 // Access: Published, Virtual 01259 // Description: Used to sort different buffers to ensure they 01260 // correspond to the same source frame, particularly 01261 // important when synchronizing the different pages of a 01262 // multi-page texture. 01263 // 01264 // Returns 0 if the two buffers are of the same frame, 01265 // <0 if this one comes earlier than the other one, and 01266 // >0 if the other one comes earlier. 01267 //////////////////////////////////////////////////////////////////// 01268 int FfmpegVideoCursor::FfmpegBuffer:: 01269 compare_timestamp(const Buffer *other) const { 01270 const FfmpegBuffer *fother; 01271 DCAST_INTO_R(fother, other, 0); 01272 if (_end_frame * _video_timebase <= fother->_begin_frame * fother->_video_timebase) { 01273 return -1; 01274 } else if (_begin_frame * _video_timebase >= fother->_end_frame * fother->_video_timebase) { 01275 return 1; 01276 } 01277 return 0; 01278 } 01279 01280 //////////////////////////////////////////////////////////////////// 01281 // Function: FfmpegVideoCursor::FfmpegBuffer::get_timestamp 01282 // Access: Published, Virtual 01283 // Description: Returns the nearest timestamp value of this 01284 // particular buffer. Ideally, 01285 // MovieVideoCursor::set_time() for this timestamp would 01286 // return this buffer again. This need be defined only 01287 // if compare_timestamp() is also defined. 01288 //////////////////////////////////////////////////////////////////// 01289 double FfmpegVideoCursor::FfmpegBuffer:: 01290 get_timestamp() const { 01291 int mid_frame = (_begin_frame + _end_frame - 1) / 2; 01292 return mid_frame * _video_timebase; 01293 } 01294 01295 #endif // HAVE_FFMPEG