]> git.sesse.net Git - casparcg/commitdiff
2.0.0.2:
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Fri, 13 May 2011 23:58:07 +0000 (23:58 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Fri, 13 May 2011 23:58:07 +0000 (23:58 +0000)
  -ffmpeg_producer: Implemented frame-seeking. New syntax (see last element):
         LOADBG [channel:int]{-[layer:int]|-0} [clip:string] {[loop:LOOP]}
 {[transition:CUT,MIX,PUSH,WIPE] [duration:uint] {[tween:string]|linear}
 {[direction:LEFT,RIGHT]|RIGHT}|CUT 0} {([start_frame:uint]{,[end_frame:uint]})|(0)}
  -amcp_protocol: Added PARAM command to call param methods on producers (currently no implementation uses this).

git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@736 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

17 files changed:
common/memory/safe_ptr.h
core/producer/frame_producer_device.cpp
core/producer/frame_producer_device.h
core/producer/layer.h
core/producer/separated/separated_producer.cpp
core/producer/transition/transition_producer.cpp
modules/ffmpeg/ffmpeg.vcxproj
modules/ffmpeg/ffmpeg.vcxproj.filters
modules/ffmpeg/producer/audio/audio_decoder.cpp
modules/ffmpeg/producer/audio/audio_decoder.h
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/input.cpp
modules/ffmpeg/producer/input.h
modules/ffmpeg/producer/video/video_decoder.cpp
modules/ffmpeg/producer/video/video_decoder.h
protocol/amcp/AMCPCommandsImpl.cpp
protocol/amcp/AMCPCommandsImpl.h

index cd92f78be6b651c929085cbdb3ead615e7134a97..fb8cfeb5c6d052f51a957f308385a9820179f105 100644 (file)
@@ -248,9 +248,9 @@ safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2, P3&& p3)
 }\r
 \r
 template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4>\r
-safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&&)\r
+safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4)\r
 {\r
-       return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P3>(p4)));\r
+       return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4)));\r
 }\r
 \r
 }
\ No newline at end of file
index 0b089f71e18befc26a56fc599edc9fc3b589876e..64854b33c4bb68ac85764cfb3274a0e0671fcab1 100644 (file)
@@ -206,6 +206,11 @@ public:
        {\r
                return executor_.begin_invoke([=]{return layers_[index].foreground();});\r
        }\r
+       \r
+       boost::unique_future<safe_ptr<frame_producer>> background(int index)\r
+       {\r
+               return executor_.begin_invoke([=]{return layers_[index].background();});\r
+       }\r
 };\r
 \r
 frame_producer_device::frame_producer_device(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
@@ -220,5 +225,6 @@ void frame_producer_device::clear(int index){impl_->clear(index);}
 void frame_producer_device::clear(){impl_->clear();}\r
 void frame_producer_device::swap_layer(int index, size_t other_index){impl_->swap_layer(index, other_index);}\r
 void frame_producer_device::swap_layer(int index, size_t other_index, frame_producer_device& other){impl_->swap_layer(index, other_index, other);}\r
-boost::unique_future<safe_ptr<frame_producer>> frame_producer_device::foreground(size_t index) {       return impl_->foreground(index);}\r
+boost::unique_future<safe_ptr<frame_producer>> frame_producer_device::foreground(size_t index) {return impl_->foreground(index);}\r
+boost::unique_future<safe_ptr<frame_producer>> frame_producer_device::background(size_t index) {return impl_->background(index);}\r
 }}
\ No newline at end of file
index 5bbfe97d2d8e4bbe7f2a891b731e57b23e79ebd5..79b5d64b51c8706e7b8b83d3a0988f1a42a3d035 100644 (file)
@@ -64,6 +64,7 @@ public:
        void swap_layer(int index, size_t other_index);\r
        void swap_layer(int index, size_t other_index, frame_producer_device& other);\r
        boost::unique_future<safe_ptr<frame_producer>> foreground(size_t index);\r
+       boost::unique_future<safe_ptr<frame_producer>> background(size_t index);\r
 \r
 private:\r
        struct implementation;\r
index b5281ff018f33a4e52d11c08589f84f72206636e..2aab7b3876a8c15e047a16c7e99f261e1687b36e 100644 (file)
@@ -44,6 +44,7 @@ public:
        void play(); // nothrow\r
        void pause(); // nothrow\r
        void stop(); // nothrow\r
+       void param(const std::wstring& param);\r
 \r
        safe_ptr<frame_producer> foreground() const; // nothrow\r
        safe_ptr<frame_producer> background() const; // nothrow\r
index bd69d8789073a1c52ead4a8b4158c6035efa1c30..b159fdf6db905d1f82d6f55aad360bd0313f163b 100644 (file)
@@ -30,14 +30,14 @@ namespace caspar { namespace core {
 struct separated_producer : public frame_producer\r
 {              \r
        safe_ptr<frame_producer>        fill_producer_;\r
-       safe_ptr<frame_producer>        key_producer;\r
+       safe_ptr<frame_producer>        key_producer_;\r
        safe_ptr<basic_frame>           last_fill_;\r
        safe_ptr<basic_frame>           last_key_;\r
        safe_ptr<basic_frame>           last_frame_;\r
                \r
        explicit separated_producer(const safe_ptr<frame_producer>& fill, const safe_ptr<frame_producer>& key) \r
                : fill_producer_(fill)\r
-               , key_producer(key)\r
+               , key_producer_(key)\r
                , last_fill_(core::basic_frame::empty())\r
                , last_key_(core::basic_frame::empty())\r
                , last_frame_(core::basic_frame::empty()){}\r
@@ -56,7 +56,7 @@ struct separated_producer : public frame_producer
                        [&]\r
                        {\r
                                if(last_key_ == core::basic_frame::empty())\r
-                                       last_key_ = receive_and_follow(key_producer);\r
+                                       last_key_ = receive_and_follow(key_producer_);\r
                        }\r
                );\r
 \r
index 7f09532a6a86b1e8d8f06e26bac169f3bc480f45..f1a03db4fd0865ff2c9964c3eceda33d7725d7ec 100644 (file)
@@ -96,9 +96,6 @@ struct transition_producer : public frame_producer
                                                \r
        safe_ptr<basic_frame> compose(const safe_ptr<basic_frame>& dest_frame, const safe_ptr<basic_frame>& src_frame) \r
        {       \r
-               if(dest_frame == basic_frame::eof() && src_frame == basic_frame::eof())\r
-                       return basic_frame::eof();\r
-\r
                if(info_.type == transition::cut)               \r
                        return src_frame;\r
                                                                                \r
index 8730803ab6295a751d48962d75267179937bd10e..936571a063f7b93936e211b74b280dd1d5120ed0 100644 (file)
   <ItemGroup>\r
     <ClInclude Include="consumer\ffmpeg_consumer.h" />\r
     <ClInclude Include="ffmpeg.h" />\r
+    <ClInclude Include="ffmpeg_error.h" />\r
     <ClInclude Include="producer\audio\audio_decoder.h" />\r
     <ClInclude Include="producer\ffmpeg_producer.h" />\r
     <ClInclude Include="producer\input.h" />\r
index f64695350b500aca3e5f855dac2ba85b0a1565c5..92841f9e89cb79ad658b02cbbb1eea7c9219be46 100644 (file)
@@ -51,5 +51,6 @@
     </ClInclude>\r
     <ClInclude Include="StdAfx.h" />\r
     <ClInclude Include="ffmpeg.h" />\r
+    <ClInclude Include="ffmpeg_error.h" />\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 5fc6b4620bf31bb7deb053167d65ae228575b171..0919bb79c6c63e4ab83f7f1696cd4c3a73ac077a 100644 (file)
@@ -42,7 +42,7 @@ struct audio_decoder::implementation : boost::noncopyable
 {\r
        typedef std::vector<short, tbb::cache_aligned_allocator<short>> buffer;\r
        \r
-       AVCodecContext* codec_context_;\r
+       AVCodecContext* codec_context_;\r
 \r
        buffer audio_buffer_;   \r
        buffer current_chunk_;\r
@@ -62,10 +62,19 @@ public:
                        BOOST_THROW_EXCEPTION(null_argument() << arg_name_info("codec_context"));                                               \r
        }\r
                \r
-       std::vector<std::vector<short>> execute(const aligned_buffer& audio_packet)\r
-       {                       \r
+       std::vector<std::vector<short>> execute(const std::shared_ptr<aligned_buffer>& audio_packet)\r
+       {                               \r
+               if(!audio_packet)\r
+                       return std::vector<std::vector<short>>();\r
+\r
+               if(audio_packet->empty()) // Need to flush\r
+               {\r
+                       avcodec_flush_buffers(codec_context_);\r
+                       return std::vector<std::vector<short>>();\r
+               }\r
+\r
                int written_bytes = audio_buffer_.size()*2 - FF_INPUT_BUFFER_PADDING_SIZE;\r
-               const int errn = avcodec_decode_audio2(codec_context_, audio_buffer_.data(), &written_bytes, audio_packet.data(), audio_packet.size());\r
+               const int errn = avcodec_decode_audio2(codec_context_, audio_buffer_.data(), &written_bytes, audio_packet->data(), audio_packet->size());\r
 \r
                if(errn < 0 || codec_context_->sample_rate != SAMPLE_RATE || codec_context_->channels != 2)\r
                {       \r
@@ -91,5 +100,5 @@ public:
 };\r
 \r
 audio_decoder::audio_decoder(AVCodecContext* codec_context, double fps) : impl_(new implementation(codec_context, fps)){}\r
-std::vector<std::vector<short>> audio_decoder::execute(const aligned_buffer& audio_packet){return impl_->execute(audio_packet);}\r
+std::vector<std::vector<short>> audio_decoder::execute(const std::shared_ptr<aligned_buffer>& audio_packet){return impl_->execute(audio_packet);}\r
 }
\ No newline at end of file
index 3de095da4c8f0bee910da8899d4f4274524f6f74..aa04c45709839282272146f75c31a888a512fc3d 100644 (file)
@@ -36,7 +36,7 @@ class audio_decoder : boost::noncopyable
 {\r
 public:\r
        explicit audio_decoder(AVCodecContext* codec_context, double fps);\r
-       std::vector<std::vector<short>> execute(const aligned_buffer& audio_packet);\r
+       std::vector<std::vector<short>> execute(const std::shared_ptr<aligned_buffer>& audio_packet);\r
 private:\r
        struct implementation;\r
        std::shared_ptr<implementation> impl_;\r
index 99cf619d4a8287c49b35bbd9adc7f390d7f00f3a..7229997e406839683981755cb58ecca7499a8446 100644 (file)
@@ -65,12 +65,12 @@ struct ffmpeg_producer : public core::frame_producer
        std::unique_ptr<video_decoder>          video_decoder_;\r
        std::unique_ptr<audio_decoder>          audio_decoder_;\r
 public:\r
-       explicit ffmpeg_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, bool loop) \r
+       explicit ffmpeg_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, bool loop, int start_frame, int end_frame\r
                : filename_(filename)\r
                , loop_(loop) \r
                , graph_(diagnostics::create_graph(narrow(print())))\r
                , frame_factory_(frame_factory)         \r
-               , input_(safe_ptr<diagnostics::graph>(graph_), filename_, loop_)\r
+               , input_(safe_ptr<diagnostics::graph>(graph_), filename_, loop_, start_frame, end_frame)\r
                , video_decoder_(input_.get_video_codec_context().get() ? new video_decoder(input_.get_video_codec_context().get(), frame_factory) : nullptr)\r
                , audio_decoder_(input_.get_audio_codec_context().get() ? new audio_decoder(input_.get_audio_codec_context().get(), frame_factory->get_video_format_desc().fps) : nullptr)\r
        {\r
@@ -117,9 +117,9 @@ public:
                return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"]";\r
        }\r
 \r
-       void try_decode_video_packet(const aligned_buffer& video_packet)\r
+       void try_decode_video_packet(const std::shared_ptr<aligned_buffer>& video_packet)\r
        {\r
-               if(!video_packet.empty() && video_decoder_) // Video Decoding.\r
+               if(video_decoder_) // Video Decoding.\r
                {\r
                        try\r
                        {\r
@@ -136,9 +136,9 @@ public:
                }\r
        }\r
 \r
-       void try_decode_audio_packet(const aligned_buffer& audio_packet)\r
+       void try_decode_audio_packet(const std::shared_ptr<aligned_buffer>& audio_packet)\r
        {\r
-               if(audio_chunk_buffer_.size() < 3 && !audio_packet.empty() && audio_decoder_) // Audio Decoding.\r
+               if(audio_decoder_) // Audio Decoding.\r
                {\r
                        try\r
                        {\r
@@ -223,8 +223,25 @@ safe_ptr<core::frame_producer> create_ffmpeg_producer(const safe_ptr<core::frame
 \r
        std::wstring path = filename + L"." + *ext;\r
        bool loop = std::find(params.begin(), params.end(), L"LOOP") != params.end();\r
+\r
+       static const boost::wregex expr(L"\\((?<START>\\d+)(,(?<END>\\d+)?)?\\)");//(,(?<END>\\d+))?\\]"); // boost::regex has no repeated captures?\r
+       boost::wsmatch what;\r
+       auto it = std::find_if(params.begin(), params.end(), [&](const std::wstring& str)\r
+       {\r
+               return boost::regex_match(str, what, expr);\r
+       });\r
+\r
+       int start = -1;\r
+       int end = -1;\r
+\r
+       if(it != params.end())\r
+       {\r
+               start = lexical_cast_or_default(what["START"].str(), -1);\r
+               if(what["END"].matched)\r
+                       end = lexical_cast_or_default(what["END"].str(), -1);\r
+       }\r
        \r
-       return make_safe<ffmpeg_producer>(frame_factory, path, loop);\r
+       return make_safe<ffmpeg_producer>(frame_factory, path, loop, start, end);\r
 }\r
 \r
 }
\ No newline at end of file
index 3647fdadd10c31c91b5f41b476371cc0212f9812..df77ffcb69cb780592429c799eb38dd2afe1dda8 100644 (file)
@@ -20,6 +20,7 @@
 #include "..\stdafx.h"\r
 \r
 #include "input.h"\r
+#include "../ffmpeg_error.h"\r
 \r
 #include <core/video_format.h>\r
 \r
@@ -32,6 +33,7 @@
 #include <boost/exception/error_info.hpp>\r
 #include <boost/thread/once.hpp>\r
 #include <boost/thread/thread.hpp>\r
+#include <boost/regex.hpp>\r
 \r
 #include <errno.h>\r
 #include <system_error>\r
@@ -65,6 +67,9 @@ struct input::implementation : boost::noncopyable
        bool loop_;\r
        int video_s_index_;\r
        int     audio_s_index_;\r
+       const int start_frame_;\r
+       const int end_frame_;\r
+       int eof_count_;\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
@@ -75,14 +80,23 @@ struct input::implementation : boost::noncopyable
        std::exception_ptr exception_;\r
        executor executor_;\r
 public:\r
-       explicit implementation(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop) \r
+       explicit implementation(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, int start_frame, int end_frame\r
                : graph_(graph)\r
                , loop_(loop)\r
                , video_s_index_(-1)\r
                , audio_s_index_(-1)\r
                , filename_(filename)\r
                , executor_(print())\r
+               , start_frame_(std::max(start_frame, 0))\r
+               , end_frame_(end_frame)\r
+               , eof_count_(end_frame-start_frame)\r
        {                       \r
+               if(end_frame_ > 0 && end_frame <= start_frame_)\r
+                       BOOST_THROW_EXCEPTION(\r
+                               invalid_argument() << \r
+                               source_info(narrow(print())) << \r
+                               msg_info("End-frame cannot be lower than start-frame."));       \r
+\r
                graph_->set_color("input-buffer", diagnostics::color(1.0f, 1.0f, 0.0f));\r
                graph_->set_color("seek", diagnostics::color(0.5f, 1.0f, 0.5f));        \r
 \r
@@ -92,6 +106,7 @@ public:
                        BOOST_THROW_EXCEPTION(\r
                                file_read_error() << \r
                                source_info(narrow(print())) << \r
+                               msg_info(av_error_str(errn)) <<\r
                                boost::errinfo_api_function("av_open_input_file") <<\r
                                boost::errinfo_errno(AVUNERROR(errn)) <<\r
                                boost::errinfo_file_name(narrow(filename)));\r
@@ -102,6 +117,7 @@ public:
                        BOOST_THROW_EXCEPTION(\r
                                file_read_error() << \r
                                source_info(narrow(print())) << \r
+                               msg_info(av_error_str(errn)) <<\r
                                boost::errinfo_api_function("av_find_stream_info") <<\r
                                boost::errinfo_errno(AVUNERROR(errn)));\r
 \r
@@ -120,9 +136,13 @@ public:
                if(!video_codec_context_ && !audio_codex_context_)\r
                        BOOST_THROW_EXCEPTION(\r
                                file_read_error() << \r
+                               msg_info(av_error_str(errn)) <<\r
                                source_info(narrow(print())) << \r
-                               msg_info("No video or audio codec context found."));            \r
-                       \r
+                               msg_info("No video or audio codec context found."));    \r
+               \r
+               if(start_frame_ != 0)                   \r
+                       seek_frame(start_frame_);\r
+                                       \r
                executor_.start();\r
                executor_.begin_invoke([this]{read_file();});\r
                CASPAR_LOG(info) << print() << " Started.";\r
@@ -150,8 +170,6 @@ public:
                \r
                if(stream == streams_end) \r
                        return nullptr;\r
-\r
-               s_index = (*stream)->index;\r
                \r
                auto codec = avcodec_find_decoder((*stream)->codec->codec_id);                  \r
                if(codec == nullptr)\r
@@ -159,9 +177,24 @@ public:
                        \r
                if((-avcodec_open((*stream)->codec, codec)) > 0)                \r
                        return nullptr;\r
+               \r
+               s_index = (*stream)->index;\r
 \r
                return std::shared_ptr<AVCodecContext>((*stream)->codec, avcodec_close);\r
        }\r
+       \r
+       std::shared_ptr<AVCodecContext>& get_default_context()\r
+       {\r
+               return video_codec_context_ ? video_codec_context_ : audio_codex_context_;\r
+       }\r
+\r
+       bool is_eof(int errn)\r
+       {\r
+               if(end_frame_ != -1)\r
+                       return get_default_context()->frame_number > eof_count_;                \r
+\r
+               return errn == AVERROR_EOF || errn == AVERROR_IO;\r
+       }\r
                \r
        void read_file()\r
        {               \r
@@ -171,20 +204,14 @@ public:
                        safe_ptr<AVPacket> read_packet(&tmp_packet, av_free_packet);    \r
 \r
                        auto read_frame_ret = av_read_frame(format_context_.get(), read_packet.get());\r
-                       if(read_frame_ret == AVERROR_EOF || read_frame_ret == AVERROR_IO)\r
+                       if(is_eof(read_frame_ret))\r
                        {\r
                                if(loop_)\r
                                {\r
-                                       auto seek_frame_ret = av_seek_frame(format_context_.get(), -1, 0, AVSEEK_FLAG_BACKWARD);\r
-                                       if(seek_frame_ret >= 0)\r
-                                               graph_->add_tag("seek");\r
-                                       else\r
-                                       {\r
-                                               BOOST_THROW_EXCEPTION(\r
-                                                       invalid_operation() <<\r
-                                                       boost::errinfo_api_function("av_seek_frame") <<\r
-                                                       boost::errinfo_errno(AVUNERROR(seek_frame_ret)));\r
-                                       }       \r
+                                       seek_frame(start_frame_, AVSEEK_FLAG_BACKWARD);\r
+                                       // AVCodecContext.frame_number is not reset. Increase the target frame_number.\r
+                                       eof_count_ += end_frame_ - start_frame_; \r
+                                       graph_->add_tag("seek");        \r
                                }       \r
                                else\r
                                        stop();\r
@@ -193,6 +220,8 @@ public:
                        {\r
                                BOOST_THROW_EXCEPTION(\r
                                        invalid_operation() <<\r
+                                       msg_info(av_error_str(read_frame_ret)) <<\r
+                                       source_info(narrow(print())) << \r
                                        boost::errinfo_api_function("av_read_frame") <<\r
                                        boost::errinfo_errno(AVUNERROR(read_frame_ret)));\r
                        }\r
@@ -204,7 +233,7 @@ public:
                                else if(read_packet->stream_index == audio_s_index_)    \r
                                        audio_packet_buffer_.try_push(std::move(packet));       \r
                        }\r
-                       \r
+                                               \r
                        graph_->update_value("input-buffer", static_cast<float>(video_packet_buffer_.size())/static_cast<float>(PACKET_BUFFER_COUNT));          \r
                }\r
                catch(...)\r
@@ -213,7 +242,7 @@ public:
                        CASPAR_LOG_CURRENT_EXCEPTION();\r
                        return;\r
                }\r
-               \r
+                               \r
                executor_.begin_invoke([this]{read_file();});           \r
                boost::unique_lock<boost::mutex> lock(mutex_);\r
                while(executor_.is_running() && audio_packet_buffer_.size() > PACKET_BUFFER_COUNT && video_packet_buffer_.size() > PACKET_BUFFER_COUNT)\r
@@ -226,12 +255,12 @@ public:
                CASPAR_LOG(info) << print() << " eof";\r
        }\r
                \r
-       aligned_buffer get_video_packet()\r
+       std::shared_ptr<aligned_buffer> get_video_packet()\r
        {\r
                return get_packet(video_packet_buffer_);\r
        }\r
 \r
-       aligned_buffer get_audio_packet()\r
+       std::shared_ptr<aligned_buffer> get_audio_packet()\r
        {\r
                return get_packet(audio_packet_buffer_);\r
        }\r
@@ -241,30 +270,50 @@ public:
                return !video_packet_buffer_.empty() || !audio_packet_buffer_.empty();\r
        }\r
        \r
-       aligned_buffer get_packet(tbb::concurrent_bounded_queue<std::shared_ptr<aligned_buffer>>& buffer)\r
+       void seek_frame(int64_t frame, int flags = 0)\r
+       {       \r
+               // Convert from frames into seconds.\r
+               auto ts = frame*static_cast<int64_t>((AV_TIME_BASE*get_default_context()->time_base.num) / get_default_context()->time_base.den);\r
+\r
+               const int errn = av_seek_frame(format_context_.get(), -1, ts, flags | AVSEEK_FLAG_FRAME);\r
+\r
+               if(errn < 0)\r
+                       BOOST_THROW_EXCEPTION(\r
+                               invalid_operation() << \r
+                               source_info(narrow(print())) << \r
+                               msg_info(av_error_str(errn)) <<\r
+                               boost::errinfo_api_function("seek_frame") <<\r
+                               boost::errinfo_errno(AVUNERROR(errn)));\r
+               \r
+               // Notify decoders to flush buffers.\r
+               video_packet_buffer_.try_push(std::make_shared<aligned_buffer>());      \r
+               audio_packet_buffer_.try_push(std::make_shared<aligned_buffer>());\r
+       }\r
+       \r
+       std::shared_ptr<aligned_buffer> get_packet(tbb::concurrent_bounded_queue<std::shared_ptr<aligned_buffer>>& buffer)\r
        {\r
                cond_.notify_all();\r
                std::shared_ptr<aligned_buffer> packet;\r
-               return buffer.try_pop(packet) ? std::move(*packet) : aligned_buffer();\r
+               return buffer.try_pop(packet) ? packet : nullptr;\r
        }\r
                        \r
-       double fps() const\r
+       double fps()\r
        {\r
-               return static_cast<double>(video_codec_context_->time_base.den) / static_cast<double>(video_codec_context_->time_base.num);\r
+               return static_cast<double>(get_default_context()->time_base.den) / static_cast<double>(get_default_context()->time_base.num);\r
        }\r
 \r
        std::wstring print() const\r
        {\r
-               return L"ffmpeg_input";\r
+               return L"ffmpeg_input[" + filename_ + L"]";\r
        }\r
 };\r
 \r
-input::input(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop) : impl_(new implementation(graph, filename, loop)){}\r
+input::input(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, int start_frame, int end_frame) : impl_(new implementation(graph, filename, loop, start_frame, end_frame)){}\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::has_packet() const{return impl_->has_packet();}\r
 bool input::is_running() const {return impl_->executor_.is_running();}\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
+std::shared_ptr<aligned_buffer> input::get_video_packet(){return impl_->get_video_packet();}\r
+std::shared_ptr<aligned_buffer> input::get_audio_packet(){return impl_->get_audio_packet();}\r
 double input::fps() const { return impl_->fps(); }\r
 }
\ No newline at end of file
index 696f7aa372b2294190b57dd7e945da2a78dd3327..fa0776012bc69b23c13fa9b399efd63d63cd9eec 100644 (file)
@@ -35,12 +35,12 @@ typedef std::vector<unsigned char, tbb::cache_aligned_allocator<unsigned char>>
 class input : boost::noncopyable\r
 {\r
 public:\r
-       explicit input(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop);\r
+       explicit input(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, int start_frame, int end_frame);\r
        const std::shared_ptr<AVCodecContext>& get_video_codec_context() const;\r
        const std::shared_ptr<AVCodecContext>& get_audio_codec_context() const;\r
 \r
-       aligned_buffer get_video_packet();\r
-       aligned_buffer get_audio_packet();\r
+       std::shared_ptr<aligned_buffer> get_video_packet();\r
+       std::shared_ptr<aligned_buffer> get_audio_packet();\r
 \r
        bool has_packet() const;\r
        bool is_running() const;\r
index 589faa1befe1cbee7cc5df42aabbd9d1b8397a6a..cb721bad7373b1f703cbb716d372066af0dbdbda 100644 (file)
@@ -20,6 +20,7 @@
 #include "../../stdafx.h"\r
 \r
 #include "video_decoder.h"\r
+#include "../../ffmpeg_error.h"\r
 \r
 #include <common/memory/memcpy.h>\r
 \r
@@ -113,15 +114,13 @@ core::pixel_format_desc get_pixel_format_desc(PixelFormat pix_fmt, size_t width,
 \r
 struct video_decoder::implementation : boost::noncopyable\r
 {      \r
-       std::shared_ptr<core::frame_factory> frame_factory_;\r
-       std::shared_ptr<SwsContext> sws_context_;\r
-\r
-       AVCodecContext* codec_context_;\r
-\r
-       const int width_;\r
-       const int height_;\r
-       const PixelFormat pix_fmt_;\r
-       core::pixel_format_desc desc_;\r
+       std::shared_ptr<SwsContext>                                     sws_context_;\r
+       const std::shared_ptr<core::frame_factory>      frame_factory_;\r
+       AVCodecContext*                                                         codec_context_;\r
+       const int                                                                       width_;\r
+       const int                                                                       height_;\r
+       const PixelFormat                                                       pix_fmt_;\r
+       core::pixel_format_desc                                         desc_;\r
 \r
 public:\r
        explicit implementation(AVCodecContext* codec_context, const safe_ptr<core::frame_factory>& frame_factory) \r
@@ -146,17 +145,27 @@ public:
                }\r
        }\r
        \r
-       std::shared_ptr<core::write_frame> execute(void* tag, const aligned_buffer& video_packet)\r
+       std::shared_ptr<core::write_frame> execute(void* tag, const std::shared_ptr<aligned_buffer>& video_packet)\r
        {                               \r
+               if(!video_packet)\r
+                       return nullptr;\r
+\r
+               if(video_packet->empty()) // Need to flush\r
+               {\r
+                       avcodec_flush_buffers(codec_context_);\r
+                       return nullptr;\r
+               }\r
+\r
                safe_ptr<AVFrame> decoded_frame(avcodec_alloc_frame(), av_free);\r
 \r
                int frame_finished = 0;\r
-               const int errn = avcodec_decode_video(codec_context_, decoded_frame.get(), &frame_finished, video_packet.data(), video_packet.size());\r
+               const int errn = avcodec_decode_video(codec_context_, decoded_frame.get(), &frame_finished, video_packet->data(), video_packet->size());\r
                \r
                if(errn < 0)\r
                {\r
                        BOOST_THROW_EXCEPTION(\r
                                invalid_operation() <<\r
+                               msg_info(av_error_str(errn)) <<\r
                                boost::errinfo_api_function("avcodec_decode_video") <<\r
                                boost::errinfo_errno(AVUNERROR(errn)));\r
                }\r
@@ -200,6 +209,6 @@ public:
 };\r
 \r
 video_decoder::video_decoder(AVCodecContext* codec_context, const safe_ptr<core::frame_factory>& frame_factory) : impl_(new implementation(codec_context, frame_factory)){}\r
-std::shared_ptr<core::write_frame> video_decoder::execute(void* tag, const aligned_buffer& video_packet){return impl_->execute(tag, video_packet);}\r
+std::shared_ptr<core::write_frame> video_decoder::execute(void* tag, const std::shared_ptr<aligned_buffer>& video_packet){return impl_->execute(tag, video_packet);}\r
 \r
 }
\ No newline at end of file
index 7676bafd9e4f7026f096f76c14c208db5c42a786..6a2c5bdb75f151281b5b703829c662cc8dd800ee 100644 (file)
@@ -33,7 +33,7 @@ class video_decoder : boost::noncopyable
 {\r
 public:\r
        explicit video_decoder(AVCodecContext* codec_context, const safe_ptr<core::frame_factory>& frame_factory);\r
-       std::shared_ptr<core::write_frame> execute(void* tag, const aligned_buffer& video_packet);      \r
+       std::shared_ptr<core::write_frame> execute(void* tag, const std::shared_ptr<aligned_buffer>& video_packet);     \r
 private:\r
        struct implementation;\r
        safe_ptr<implementation> impl_;\r
index cbfc6c0884d9de5d9d8c6b1bbc3b73e799f246f5..d6620ffb015837fba398de7a070cd33b79e51d50 100644 (file)
@@ -170,6 +170,31 @@ void AMCPCommand::Clear()
        _parameters.clear();\r
 }\r
 \r
+bool ParamCommand::DoExecute()\r
+{      \r
+       //Perform loading of the clip\r
+       try\r
+       {\r
+               auto what = _parameters.at(2);\r
+               if(what == L"B")\r
+                       GetChannel()->producer()->background(GetLayerIndex()).get()->param(_parameters.at(3));\r
+               else if(what == L"F")\r
+                       GetChannel()->producer()->foreground(GetLayerIndex()).get()->param(_parameters.at(3));\r
+       \r
+               CASPAR_LOG(info) << "Executed param: " <<  _parameters[0] << TEXT(" successfully");\r
+\r
+               SetReplyString(TEXT("202 PARAM OK\r\n"));\r
+\r
+               return true;\r
+       }\r
+       catch(...)\r
+       {\r
+               CASPAR_LOG_CURRENT_EXCEPTION();\r
+               SetReplyString(TEXT("502 PARAM FAILED\r\n"));\r
+               return false;\r
+       }\r
+}\r
+\r
 bool MixerCommand::DoExecute()\r
 {      \r
        //Perform loading of the clip\r
index c1ac74d4e99cf6470ed303cad673f918cafc3afe..785a2f1180ee4051d7e99d6a83f770244eb9bae3 100644 (file)
@@ -29,6 +29,12 @@ std::wstring ListMedia();
 std::wstring ListTemplates();\r
 \r
 namespace amcp {\r
+       \r
+class ParamCommand : public AMCPCommandBase<true, AddToQueue, 2>\r
+{\r
+       std::wstring print() const { return L"ParamCommand";}\r
+       bool DoExecute();\r
+};\r
 \r
 class MixerCommand : public AMCPCommandBase<true, AddToQueue, 2>\r
 {\r