]> git.sesse.net Git - casparcg/blobdiff - core/producer/ffmpeg/input.cpp
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
[casparcg] / core / producer / ffmpeg / input.cpp
index 25725288f6e6359523bde1a942d6b5214caa6bbd..bc4c240ceae3ebd9a89735267b014ad00b1bfdf8 100644 (file)
@@ -2,9 +2,10 @@
 \r
 #include "input.h"\r
 \r
-#include "../../format/video_format.h"\r
+#include "../../video_format.h"\r
 \r
 #include <common/concurrency/executor.h>\r
+#include <common/diagnostics/graph.h>\r
 \r
 #include <tbb/concurrent_queue.h>\r
 #include <tbb/queuing_mutex.h>\r
@@ -19,7 +20,6 @@
 #pragma warning (disable : 4244)\r
 #endif\r
 \r
-\r
 extern "C" \r
 {\r
        #define __STDC_CONSTANT_MACROS\r
@@ -30,19 +30,38 @@ extern "C"
 namespace caspar { namespace core { namespace ffmpeg{\r
                \r
 struct input::implementation : boost::noncopyable\r
-{\r
-       static const size_t BUFFER_SIZE = 2 << 25;\r
+{              \r
+       static const size_t BUFFER_SIZE = 2 << 24;\r
 \r
-       implementation(const std::wstring& filename) : video_s_index_(-1), audio_s_index_(-1), filename_(filename)\r
-       {               \r
-               static boost::once_flag av_register_all_flag = BOOST_ONCE_INIT;\r
-               boost::call_once(av_register_all, av_register_all_flag);        \r
-               \r
-               static boost::once_flag avcodec_init_flag = BOOST_ONCE_INIT;\r
-               boost::call_once(avcodec_init, avcodec_init_flag);      \r
+       safe_ptr<diagnostics::graph> graph_;\r
+\r
+       std::shared_ptr<AVFormatContext> format_context_;       // Destroy this last\r
+\r
+       std::shared_ptr<AVCodecContext> video_codec_context_;\r
+       std::shared_ptr<AVCodecContext> audio_codex_context_;\r
+       \r
+       const std::wstring filename_;\r
+\r
+       bool loop_;\r
+       int video_s_index_;\r
+       int     audio_s_index_;\r
+\r
+       tbb::atomic<size_t>     buffer_size_;\r
+       \r
+       tbb::concurrent_bounded_queue<std::shared_ptr<aligned_buffer>> video_packet_buffer_;\r
+       tbb::concurrent_bounded_queue<std::shared_ptr<aligned_buffer>> audio_packet_buffer_;\r
+       \r
+       executor executor_;\r
+public:\r
+       explicit implementation(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop) \r
+               : graph_(graph)\r
+               , loop_(loop)\r
+               , video_s_index_(-1)\r
+               , audio_s_index_(-1)\r
+               , filename_(filename)\r
+       {                       \r
+               graph_->set_color("input_buffer_size", diagnostics::color(0.0f, 1.0f, 1.0f));           \r
 \r
-               loop_ = false;  \r
-               \r
                int errn;\r
                AVFormatContext* weak_format_context_;\r
                if((errn = -av_open_input_file(&weak_format_context_, narrow(filename).c_str(), nullptr, 0, nullptr)) > 0)\r
@@ -72,7 +91,7 @@ struct input::implementation : boost::noncopyable
 \r
                if(!video_codec_context_ && !audio_codex_context_)\r
                        BOOST_THROW_EXCEPTION(file_read_error() << msg_info("No video or audio codec context found."));         \r
-                       \r
+                                       \r
                executor_.start();\r
                executor_.begin_invoke([this]{read_file();});\r
                CASPAR_LOG(info) << print() << " started.";\r
@@ -80,6 +99,7 @@ struct input::implementation : boost::noncopyable
 \r
        ~implementation()\r
        {\r
+               executor_.clear();\r
                CASPAR_LOG(info) << print() << " ended.";\r
        }\r
                                                        \r
@@ -110,7 +130,6 @@ struct input::implementation : boost::noncopyable
                {\r
                        AVPacket tmp_packet;\r
                        safe_ptr<AVPacket> read_packet(&tmp_packet, av_free_packet);    \r
-                       tbb::queuing_mutex::scoped_lock lock(seek_mutex_);      \r
 \r
                        if (av_read_frame(format_context_.get(), read_packet.get()) >= 0) // NOTE: read_packet is only valid until next call of av_safe_ptr<read_frame> or av_close_input_file\r
                        {\r
@@ -118,7 +137,7 @@ struct input::implementation : boost::noncopyable
                                if(read_packet->stream_index == video_s_index_)                                                 \r
                                {\r
                                        buffer_size_ += packet->size();\r
-                                       video_packet_buffer_.try_push(std::move(packet));                                               \r
+                                       video_packet_buffer_.try_push(std::move(packet));       \r
                                }\r
                                else if(read_packet->stream_index == audio_s_index_)    \r
                                {\r
@@ -126,10 +145,27 @@ struct input::implementation : boost::noncopyable
                                        audio_packet_buffer_.try_push(std::move(packet));\r
                                }\r
                        }\r
-                       else if(!loop_ || av_seek_frame(format_context_.get(), -1, 0, AVSEEK_FLAG_BACKWARD) < 0) // TODO: av_seek_frame does not work for all formats\r
-                               executor_.stop(executor::no_wait);\r
+                       else if(!loop_ || !seek_frame(0, AVSEEK_FLAG_BACKWARD)) // TODO: av_seek_frame does not work for all formats\r
+                               executor_.stop();\r
+                       graph_->update("input_buffer_size", static_cast<float>(buffer_size_)/static_cast<float>(BUFFER_SIZE));\r
                }\r
        }\r
+       \r
+       bool seek_frame(int64_t seek_target, int flags = 0)\r
+       {  \r
+               static const AVRational TIME_BASE_Q = {1, AV_TIME_BASE};\r
+               \r
+               int stream_index = std::max(video_s_index_, audio_s_index_);\r
+               seek_target *= AV_TIME_BASE;\r
+\r
+               if(stream_index >= 0)     \r
+                       seek_target = av_rescale_q(seek_target, TIME_BASE_Q, format_context_->streams[stream_index]->time_base);\r
+         \r
+               bool result = av_seek_frame(format_context_.get(), stream_index, seek_target, flags) >= 0;\r
+               if(!result)\r
+                       CASPAR_LOG(warning) << "Failed to seek frame.";\r
+               return result;\r
+       }\r
                \r
        aligned_buffer get_video_packet()\r
        {\r
@@ -159,16 +195,6 @@ struct input::implementation : boost::noncopyable
                return !executor_.is_running() && video_packet_buffer_.empty() && audio_packet_buffer_.empty();\r
        }\r
                \r
-       // TODO: Not properly done.\r
-       bool seek(unsigned long long seek_target)\r
-       {\r
-               tbb::queuing_mutex::scoped_lock lock(seek_mutex_);\r
-               if(av_seek_frame(format_context_.get(), -1, seek_target*AV_TIME_BASE, 0) < 0)\r
-                       return false;\r
-\r
-               return true;\r
-       }\r
-\r
        double fps() const\r
        {\r
                return static_cast<double>(video_codec_context_->time_base.den) / static_cast<double>(video_codec_context_->time_base.num);\r
@@ -178,36 +204,13 @@ struct input::implementation : boost::noncopyable
        {\r
                return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"] Buffer thread";\r
        }\r
-                               \r
-       std::shared_ptr<AVFormatContext>        format_context_;        // Destroy this last\r
-\r
-       tbb::queuing_mutex                                      seek_mutex_;\r
-\r
-       const std::wstring                                      filename_;\r
-\r
-       std::shared_ptr<AVCodecContext>         video_codec_context_;\r
-\r
-       std::shared_ptr<AVCodecContext>         audio_codex_context_;\r
-\r
-       tbb::atomic<bool>                                       loop_;\r
-       int                                                                     video_s_index_;\r
-       int                                                                     audio_s_index_;\r
-       \r
-       tbb::concurrent_bounded_queue<std::shared_ptr<aligned_buffer>> video_packet_buffer_;\r
-       tbb::concurrent_bounded_queue<std::shared_ptr<aligned_buffer>> audio_packet_buffer_;\r
-       \r
-       tbb::atomic<size_t>                     buffer_size_;\r
-\r
-       executor executor_;\r
 };\r
 \r
-input::input(const std::wstring& filename) : impl_(new implementation(filename)){}\r
-void input::set_loop(bool value){impl_->loop_ = value;}\r
+input::input(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop) : impl_(new implementation(graph, filename, loop)){}\r
 const std::shared_ptr<AVCodecContext>& input::get_video_codec_context() const{return impl_->video_codec_context_;}\r
 const std::shared_ptr<AVCodecContext>& input::get_audio_codec_context() const{return impl_->audio_codex_context_;}\r
 bool input::is_eof() const{return impl_->is_eof();}\r
 aligned_buffer input::get_video_packet(){return impl_->get_video_packet();}\r
 aligned_buffer input::get_audio_packet(){return impl_->get_audio_packet();}\r
-bool input::seek(unsigned long long frame){return impl_->seek(frame);}\r
 double input::fps() const { return impl_->fps(); }\r
 }}}
\ No newline at end of file