]> git.sesse.net Git - casparcg/commitdiff
2.0. Implemented frame-accurate auto play functionality which also takes into account...
authorRonag <Ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Tue, 2 Aug 2011 07:43:37 +0000 (07:43 +0000)
committerRonag <Ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Tue, 2 Aug 2011 07:43:37 +0000 (07:43 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@1036 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

13 files changed:
core/producer/frame_producer.h
core/producer/layer.cpp
core/producer/layer.h
core/producer/stage.cpp
core/producer/stage.h
modules/ffmpeg/producer/audio/audio_decoder.cpp
modules/ffmpeg/producer/audio/audio_decoder.h
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/video/video_decoder.cpp
modules/ffmpeg/producer/video/video_decoder.h
modules/image/producer/image_scroll_producer.cpp
protocol/amcp/AMCPCommandsImpl.cpp
shell/casparcg.config

index 17a4e3c75d5092bc15b447dff319871d0225f447..bf297fe648df432077e4941b33b641808ee93da7 100644 (file)
@@ -46,9 +46,11 @@ public:
        virtual safe_ptr<frame_producer> get_following_producer() const {return frame_producer::empty();}  // nothrow\r
        virtual void set_leading_producer(const safe_ptr<frame_producer>&) {}  // nothrow\r
                \r
-       static const safe_ptr<frame_producer>& empty(); // nothrow\r
+       virtual int64_t nb_frames() const {return 0;}\r
+\r
+       virtual safe_ptr<core::basic_frame> last_frame() const {return last_frame_;}\r
 \r
-       safe_ptr<core::basic_frame> last_frame() const {return last_frame_;}\r
+       static const safe_ptr<frame_producer>& empty(); // nothrow\r
        \r
 private:\r
        friend safe_ptr<basic_frame> receive(const safe_ptr<frame_producer>& producer);\r
index 0f4ec257467ef326584a227a6aa3f08448d7dea2..9ef35a0d00fe2721f398a5504304794a07dd52dc 100644 (file)
@@ -24,6 +24,9 @@
 \r
 #include "frame_producer.h"\r
 \r
+#include "frame/basic_frame.h"\r
+\r
+\r
 namespace caspar { namespace core {\r
        \r
 struct layer::implementation\r
@@ -31,17 +34,22 @@ struct layer::implementation
        safe_ptr<frame_producer>        foreground_;\r
        safe_ptr<frame_producer>        background_;\r
        bool                                            is_paused_;\r
+       int                                                     auto_play_delta_;\r
+       int64_t                                         frame_number_;\r
 public:\r
        implementation() \r
                : foreground_(frame_producer::empty())\r
                , background_(frame_producer::empty())\r
-               , is_paused_(false){}\r
+               , is_paused_(false)\r
+               , auto_play_delta_(-1){}\r
        \r
        void pause(){is_paused_ = true;}\r
        void resume(){is_paused_ = false;}\r
 \r
-       void load(const safe_ptr<frame_producer>& producer, bool preview)\r
+       void load(const safe_ptr<frame_producer>& producer, bool preview, int auto_play_delta)\r
        {               \r
+               auto_play_delta_ = auto_play_delta;\r
+\r
                background_ = producer;\r
 \r
                if(preview) // Play the first frame and pause.\r
@@ -58,6 +66,7 @@ public:
                {\r
                        background_->set_leading_producer(foreground_);\r
                        foreground_ = background_;\r
+                       frame_number_ = 0;\r
                        background_ = frame_producer::empty();\r
                }\r
                resume();\r
@@ -73,7 +82,30 @@ public:
                if(is_paused_)\r
                        return foreground_->last_frame();\r
                \r
-               return receive_and_follow_w_last(foreground_);\r
+               auto frame = receive_and_follow(foreground_);\r
+               if(frame == core::basic_frame::late())\r
+                       return foreground_->last_frame();\r
+                       \r
+               ++frame_number_;\r
+\r
+               if(auto_play_delta_ >= 0)\r
+               {\r
+                       const auto frames_left = foreground_->nb_frames() - frame_number_ - auto_play_delta_;\r
+\r
+                       if(frames_left <= 0 || frame == core::basic_frame::eof())\r
+                       {\r
+                               CASPAR_VERIFY(auto_play_delta_ != 0 || frame == core::basic_frame::eof())\r
+\r
+                               CASPAR_LOG(info) << L"Automatically playing next clip with " << auto_play_delta_ << " frames offset.";\r
+                               \r
+                               auto_play_delta_ = -1;\r
+                               play();\r
+                               frame = receive();\r
+                       }\r
+\r
+               }\r
+                               \r
+               return frame;\r
        }\r
 };\r
 \r
@@ -95,7 +127,7 @@ void layer::swap(layer& other)
 {      \r
        impl_.swap(other.impl_);\r
 }\r
-void layer::load(const safe_ptr<frame_producer>& frame_producer, bool preview){return impl_->load(frame_producer, preview);}   \r
+void layer::load(const safe_ptr<frame_producer>& frame_producer, bool preview, int auto_play_delta){return impl_->load(frame_producer, preview, auto_play_delta);}     \r
 void layer::play(){impl_->play();}\r
 void layer::pause(){impl_->pause();}\r
 void layer::stop(){impl_->stop();}\r
index 2aab7b3876a8c15e047a16c7e99f261e1687b36e..4433891b8bf17a3ae17c0b4406499ace067c1724 100644 (file)
@@ -40,7 +40,7 @@ public:
 \r
        void swap(layer& other); // nothrow \r
                \r
-       void load(const safe_ptr<frame_producer>& producer, bool preview); // nothrow\r
+       void load(const safe_ptr<frame_producer>& producer, bool preview, int auto_play_delta); // nothrow\r
        void play(); // nothrow\r
        void pause(); // nothrow\r
        void stop(); // nothrow\r
index 5796d0bc96654d953be7926d6b9f13bfa14b359d..1762c0d5f2ed6d187e785e0798f8c6973ccb8ba3 100644 (file)
@@ -107,11 +107,11 @@ public:
                return frames;\r
        }\r
 \r
-       void load(int index, const safe_ptr<frame_producer>& producer, bool preview)\r
+       void load(int index, const safe_ptr<frame_producer>& producer, bool preview, int auto_play_delta)\r
        {\r
                channel_.execution().invoke([&]\r
                {\r
-                       layers_[index].load(make_safe<destroy_producer_proxy>(channel_.destruction(), producer), preview);\r
+                       layers_[index].load(make_safe<destroy_producer_proxy>(channel_.destruction(), producer), preview, auto_play_delta);\r
                });\r
        }\r
 \r
@@ -222,7 +222,7 @@ public:
 \r
 stage::stage(video_channel_context& video_channel) : impl_(new implementation(video_channel)){}\r
 void stage::swap(stage& other){impl_->swap(other);}\r
-void stage::load(int index, const safe_ptr<frame_producer>& producer, bool preview){impl_->load(index, producer, preview);}\r
+void stage::load(int index, const safe_ptr<frame_producer>& producer, bool preview, int auto_play_delta){impl_->load(index, producer, preview, auto_play_delta);}\r
 void stage::pause(int index){impl_->pause(index);}\r
 void stage::play(int index){impl_->play(index);}\r
 void stage::stop(int index){impl_->stop(index);}\r
index a45860b269f05db3dd1155c79037f627ad12e11a..1217dc2c653c291f733a9ae177ee1601b7f2225a 100644 (file)
@@ -41,7 +41,7 @@ public:
 \r
        std::map<int, safe_ptr<basic_frame>> execute();\r
                \r
-       void load(int index, const safe_ptr<frame_producer>& producer, bool preview = false);\r
+       void load(int index, const safe_ptr<frame_producer>& producer, bool preview = false, int auto_play_delta = -1);\r
        void pause(int index);\r
        void play(int index);\r
        void stop(int index);\r
index 5b68bb558a7cabf94f1f08fe011018e466dc976c..3cd99a38f685aac411bf01c348a98c484f15b1f1 100644 (file)
@@ -51,9 +51,12 @@ struct audio_decoder::implementation : boost::noncopyable
        std::vector<int8_t,  tbb::cache_aligned_allocator<int8_t>>      buffer2_;\r
        std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>>     audio_samples_; \r
        std::queue<std::shared_ptr<AVPacket>>                                           packets_;\r
+\r
+       int64_t                                                                                                         nb_frames_;\r
 public:\r
        explicit implementation(const std::shared_ptr<AVFormatContext>& context, const core::video_format_desc& format_desc) \r
                : format_desc_(format_desc)     \r
+               , nb_frames_(0)\r
        {                          \r
                AVCodec* dec;\r
                index_ = av_find_best_stream(context.get(), AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0);\r
@@ -67,6 +70,10 @@ public:
                                \r
                codec_context_.reset(context->streams[index_]->codec, avcodec_close);\r
 \r
+               //nb_frames_ = context->streams[index_]->nb_frames;\r
+               //if(nb_frames_ == 0)\r
+               //      nb_frames_ = context->streams[index_]->duration * context->streams[index_]->time_base.den;\r
+\r
                if(codec_context_ &&\r
                   (codec_context_->sample_rate != static_cast<int>(format_desc_.audio_sample_rate) || \r
                    codec_context_->channels    != static_cast<int>(format_desc_.audio_channels)) ||\r
@@ -175,4 +182,5 @@ audio_decoder::audio_decoder(const std::shared_ptr<AVFormatContext>& context, co
 void audio_decoder::push(const std::shared_ptr<AVPacket>& packet){impl_->push(packet);}\r
 bool audio_decoder::ready() const{return impl_->ready();}\r
 std::vector<std::shared_ptr<std::vector<int16_t>>> audio_decoder::poll(){return impl_->poll();}\r
+int64_t audio_decoder::nb_frames() const{return impl_->nb_frames_;}\r
 }
\ No newline at end of file
index fc9789633499af6371395b039954a6f7b791109a..6ff023633f6f013317581dd5b7cf950e3aa18b1f 100644 (file)
@@ -41,6 +41,8 @@ public:
        bool ready() const;\r
        std::vector<std::shared_ptr<std::vector<int16_t>>> poll();\r
 \r
+       int64_t nb_frames() const;\r
+\r
 private:\r
        struct implementation;\r
        safe_ptr<implementation> impl_;\r
index 680c1fc4f72e732aea59e6733df7c0c26d232f38..f717ffef3c9bde9135b6f393fb77adf32f58e075 100644 (file)
@@ -67,6 +67,8 @@ struct ffmpeg_producer : public core::frame_producer
        \r
        tbb::task_group                                                                 tasks_;\r
 \r
+       int                                                                                             start_;\r
+\r
 public:\r
        explicit ffmpeg_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, const std::wstring& filter, bool loop, int start, int length) \r
                : filename_(filename)\r
@@ -77,6 +79,7 @@ public:
                , video_decoder_(input_.context(), frame_factory, filter)\r
                , audio_decoder_(input_.context(), frame_factory->get_video_format_desc())\r
                , muxer_(video_decoder_.fps(), format_desc_, frame_factory)\r
+               , start_(start)\r
        {\r
                graph_->add_guide("frame-time", 0.5);\r
                graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
@@ -145,6 +148,11 @@ public:
                BOOST_FOREACH(auto& video, video_frames)\r
                        muxer_.push(video);             \r
        }\r
+\r
+       virtual int64_t nb_frames() const\r
+       {\r
+               return std::max<int64_t>(0, video_decoder_.nb_frames()-start_);//std::max(video_decoder_.nb_frames(), audio_decoder_.nb_frames());\r
+       }\r
                                \r
        virtual std::wstring print() const\r
        {\r
index 5405161db6e4fe08628f4b5ee3f08476b82b12fe..bcc8207f3a3b5d1deca9243d9ac4eee955e22a81 100644 (file)
@@ -68,12 +68,14 @@ struct video_decoder::implementation : boost::noncopyable
        std::unique_ptr<filter>                                 filter_;\r
 \r
        double                                                                  fps_;\r
+       int64_t                                                                 nb_frames_;\r
 public:\r
        explicit implementation(const std::shared_ptr<AVFormatContext>& context, const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filter) \r
                : frame_factory_(frame_factory)\r
                , mode_(core::video_mode::invalid)\r
                , filter_(filter.empty() ? nullptr : new caspar::filter(filter))\r
                , fps_(frame_factory_->get_video_format_desc().fps)\r
+               , nb_frames_(0)\r
        {\r
                AVCodec* dec;\r
                index_ = av_find_best_stream(context.get(), AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);\r
@@ -86,10 +88,14 @@ public:
                        return;\r
                                \r
                codec_context_.reset(context->streams[index_]->codec, tbb_avcodec_close);\r
-\r
+               \r
                // Some files give an invalid time_base numerator, try to fix it.\r
                if(codec_context_ && codec_context_->time_base.num == 1)\r
                        codec_context_->time_base.num = static_cast<int>(std::pow(10.0, static_cast<int>(std::log10(static_cast<float>(codec_context_->time_base.den)))-1));    \r
+               \r
+               nb_frames_ = context->streams[index_]->nb_frames;\r
+               if(nb_frames_ == 0)\r
+                       nb_frames_ = context->streams[index_]->duration;// * context->streams[index_]->time_base.den;\r
 \r
                fps_ = static_cast<double>(codec_context_->time_base.den) / static_cast<double>(codec_context_->time_base.num);\r
                if(double_rate(filter))\r
@@ -207,4 +213,5 @@ std::vector<std::shared_ptr<core::write_frame>> video_decoder::poll(){return imp
 bool video_decoder::ready() const{return impl_->ready();}\r
 core::video_mode::type video_decoder::mode(){return impl_->mode();}\r
 double video_decoder::fps() const{return impl_->fps();}\r
+int64_t video_decoder::nb_frames() const{return impl_->nb_frames_;}\r
 }
\ No newline at end of file
index 57727d105648ca090d655d03c27a78842f4851d7..e60da4936f29ea00905af301391a6c6203ec8651 100644 (file)
@@ -43,6 +43,8 @@ public:
 \r
        core::video_mode::type mode();\r
 \r
+       int64_t nb_frames() const;\r
+\r
        double fps() const;\r
 private:\r
        struct implementation;\r
index 17879ee45b352245d86d4605b6191c0e5ab8261d..af78f435cdcf818333f94d3681b9f189e5161e09 100644 (file)
@@ -51,7 +51,7 @@ struct image_scroll_producer : public core::frame_producer
 {      \r
        const std::wstring                                                      filename_;\r
        std::vector<safe_ptr<core::basic_frame>>        frames_;\r
-       size_t                                                                          pixel_offset_;\r
+       size_t                                                                          delta_;\r
        core::video_format_desc                                         format_desc_;\r
        size_t                                                                          width_;\r
        size_t                                                                          height_;\r
@@ -59,7 +59,7 @@ struct image_scroll_producer : public core::frame_producer
        \r
        explicit image_scroll_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, size_t speed) \r
                : filename_(filename)\r
-               , pixel_offset_(0)\r
+               , delta_(0)\r
                , format_desc_(frame_factory->get_video_format_desc())\r
                , speed_(speed)\r
        {\r
@@ -93,39 +93,57 @@ struct image_scroll_producer : public core::frame_producer
                                frames_.push_back(frame);\r
                        }\r
                }\r
-               //else\r
-               //{\r
-               //      while(count > 0)\r
-               //      {\r
-               //              auto frame = frame_factory->create_frame(reinterpret_cast<void*>(rand()), format_desc_.width, height_);\r
-               //              if(count >= frame->image_data().size())\r
-               //              {       \r
-               //                      count -= frame->image_data().size();\r
-               //              }\r
-               //              else\r
-               //              {\r
-               //                      fast_memclr(frame->image_data().begin(), frame->image_data().size());   \r
-               //                      //std::copy_n(bytes, count, frame->image_data().begin() + format_desc_.size - count);\r
-               //                      count = 0;\r
-               //              }\r
-               //      \r
-               //              frame->commit();\r
-               //              frames_.push_back(frame);\r
-               //      }\r
-               //}\r
+               else\r
+               {\r
+                       int i = 0;\r
+                       while(count > 0)\r
+                       {\r
+                               auto frame = frame_factory->create_frame(reinterpret_cast<void*>(rand()), format_desc_.width, height_);\r
+                               if(count >= frame->image_data().size())\r
+                               {       \r
+                                       for(size_t y = 0; y < height_; ++y)\r
+                                               std::copy_n(bytes + i * format_desc_.width*4 + y * width_*4, format_desc_.width*4, frame->image_data().begin() + y * format_desc_.width*4);\r
+                                       \r
+                                       ++i;\r
+                                       count -= frame->image_data().size();\r
+                               }\r
+                               else\r
+                               {\r
+                                       //fast_memclr(frame->image_data().begin(), frame->image_data().size()); \r
+                                       //int width2 = width_ % format_desc_.width;\r
+                                       //for(size_t y = 0; y < height_; ++y)\r
+                                       //      std::copy_n(bytes + i * format_desc_.size*4 + y * width2*4, format_desc_.width*4, frame->image_data().begin() + y *  format_desc_.width*4);\r
+\r
+                                       count = 0;\r
+                               }\r
+                       \r
+                               frame->commit();\r
+                               frames_.push_back(frame);\r
+                       }\r
+               }\r
+\r
+               std::reverse(frames_.begin(), frames_.end());\r
        }\r
        \r
        // frame_producer\r
 \r
        virtual safe_ptr<core::basic_frame> receive()\r
        {\r
-               pixel_offset_ += speed_;\r
+               delta_ += speed_;\r
 \r
                if(frames_.empty())\r
                        return core::basic_frame::eof();\r
-\r
-               for(size_t n = 0; n < frames_.size(); ++n)\r
-                       frames_[n]->get_image_transform().set_fill_translation(0.0, -0.5*(n+1) + pixel_offset_ * 0.5/static_cast<double>(format_desc_.height));\r
+               \r
+               if(height_ > format_desc_.height)\r
+               {\r
+                       for(size_t n = 0; n < frames_.size(); ++n)\r
+                               frames_[n]->get_image_transform().set_fill_translation(0.0, -0.5*(n+1) + delta_ * 0.5/static_cast<double>(format_desc_.height));\r
+               }\r
+               else\r
+               {\r
+                       for(size_t n = 0; n < frames_.size(); ++n)\r
+                               frames_[n]->get_image_transform().set_fill_translation(-0.5*(n+1) + delta_ * 0.5/static_cast<double>(format_desc_.height), 0.0);\r
+               }\r
 \r
                return core::basic_frame(frames_);\r
        }\r
index 35556c39801965f0bf2a84f563ca4b920321731f..3c5563826be2b58dce75fd3e298be61131d15231 100644 (file)
@@ -674,8 +674,10 @@ bool LoadbgCommand::DoExecute()
                if(pFP == frame_producer::empty())\r
                        BOOST_THROW_EXCEPTION(file_not_found() << msg_info(_parameters.size() > 0 ? narrow(_parameters[0]) : ""));\r
 \r
+               bool auto_play = std::find(_parameters.begin(), _parameters.end(), L"AUTO") != _parameters.end();\r
+\r
                auto pFP2 = create_transition_producer(GetChannel()->get_video_format_desc().mode, pFP, transitionInfo);\r
-               GetChannel()->stage()->load(GetLayerIndex(), pFP2); // TODO: LOOP\r
+               GetChannel()->stage()->load(GetLayerIndex(), pFP2, false, auto_play ? transitionInfo.duration : -1); // TODO: LOOP\r
        \r
                CASPAR_LOG(info) << "Loaded " << _parameters[0] << TEXT(" successfully to background");\r
                SetReplyString(TEXT("202 LOADBG OK\r\n"));\r
index 5430e5f820168c5ae85f9d298f0c2692c4212bc2..cefb23a2a1ce0419672c151c45d531550ea180f7 100644 (file)
   </consumers>\r
   <channels>\r
     <channel>\r
-      <video-mode>720p5000</video-mode>\r
+      <video-mode>PAL</video-mode>\r
       <consumers>\r
-        <screen></screen>\r
+        <screen>\r
+          <device>1</device>\r
+        </screen>\r
         <audio></audio>\r
       </consumers>\r
     </channel>\r