]> git.sesse.net Git - casparcg/commitdiff
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 30 Nov 2011 23:06:16 +0000 (23:06 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 30 Nov 2011 23:06:16 +0000 (23:06 +0000)
modules/ffmpeg/consumer/ffmpeg_consumer.cpp

index 5d978260d2801fb75c19cb6a39d79bc353db6041..6f8505a55a895663001a58bb737d368f5f34acb3 100644 (file)
@@ -35,6 +35,7 @@
 #include <common/env.h>\r
 \r
 #include <boost/thread/once.hpp>\r
+#include <boost/algorithm/string.hpp>\r
 \r
 #include <tbb/cache_aligned_allocator.h>\r
 #include <tbb/parallel_invoke.h>\r
@@ -81,7 +82,7 @@ struct ffmpeg_consumer : boost::noncopyable
        std::shared_ptr<SwsContext>                             img_convert_ctx_;\r
        \r
 public:\r
-       ffmpeg_consumer(const std::string& filename, const core::video_format_desc& format_desc)\r
+       ffmpeg_consumer(const std::string& filename, const core::video_format_desc& format_desc, const std::string& codec, int bitrate)\r
                : filename_(filename + ".mov")\r
                , video_outbuf_(1920*1080*8)\r
                , audio_outbuf_(48000)\r
@@ -99,9 +100,13 @@ public:
 \r
                strcpy_s(oc_->filename, filename_.c_str());\r
                \r
+               auto video_codec = avcodec_find_encoder_by_name(codec.c_str());\r
+               if(video_codec == nullptr)\r
+                       BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info(codec));\r
+\r
                //  Add the audio and video streams using the default format codecs     and initialize the codecs .\r
-               video_st_ = add_video_stream(oc_->oformat->video_codec);\r
-               audio_st_ = add_audio_stream(oc_->oformat->audio_codec);\r
+               video_st_ = add_video_stream(video_codec->id, bitrate);\r
+               audio_st_ = add_audio_stream();\r
                                \r
                dump_format(oc_.get(), 0, filename_.c_str(), 1);\r
                 \r
@@ -111,7 +116,7 @@ public:
                                \r
                THROW_ON_ERROR2(av_write_header(oc_.get()), "[ffmpeg_consumer]");\r
 \r
-               CASPAR_LOG(info) << print() << L" Successfully initialized.";   \r
+               CASPAR_LOG(info) << print() << L" Successfully Initialized.";   \r
        }\r
 \r
        ~ffmpeg_consumer()\r
@@ -134,6 +139,8 @@ public:
 \r
                        if (!(oc_->oformat->flags & AVFMT_NOFILE)) \r
                                THROW_ON_ERROR2(avio_close(oc_->pb), "[ffmpeg_consumer]"); // Close the output ffmpeg.\r
+\r
+                       CASPAR_LOG(info) << print() << L" Successfully Uninitialized."; \r
                }\r
                catch(...)\r
                {\r
@@ -147,7 +154,7 @@ public:
                return L"ffmpeg[" + widen(filename_) + L"]";\r
        }\r
 \r
-       std::shared_ptr<AVStream> add_video_stream(enum CodecID codec_id)\r
+       std::shared_ptr<AVStream> add_video_stream(enum CodecID codec_id, int bitrate)\r
        { \r
                auto st = av_new_stream(oc_.get(), 0);\r
                if (!st) \r
@@ -156,17 +163,30 @@ public:
                                << msg_info("Could not alloc video-stream")                             \r
                                << boost::errinfo_api_function("av_new_stream"));\r
                }\r
-\r
-               st->codec->codec_id                     = CODEC_ID_DNXHD;\r
+               \r
+               st->codec->codec_id                     = codec_id;\r
                st->codec->codec_type           = AVMEDIA_TYPE_VIDEO;\r
-               st->codec->bit_rate                     = 145*1000000;\r
-               st->codec->width                        = std::min<size_t>(1280, format_desc_.width);\r
-               st->codec->height                       = std::min<size_t>(720, format_desc_.height);\r
+               st->codec->width                        = format_desc_.width;\r
+               st->codec->height                       = format_desc_.height;\r
                st->codec->time_base.den        = format_desc_.time_scale;\r
                st->codec->time_base.num        = format_desc_.duration;\r
-               st->codec->pix_fmt                      = st->codec->pix_fmt == -1 ? PIX_FMT_YUV422P : st->codec->pix_fmt;\r
-               
-               if(oc_->oformat->flags & AVFMT_GLOBALHEADER)
+\r
+               if(st->codec->codec_id == CODEC_ID_PRORES)\r
+               {                       \r
+                       st->codec->bit_rate     = bitrate > 0 ? bitrate : format_desc_.width < 1280 ? 42*1000000 : 147*1000000;\r
+                       st->codec->pix_fmt      = PIX_FMT_YUV422P10;\r
+               }\r
+               else if(st->codec->codec_id == CODEC_ID_DNXHD)\r
+               {\r
+                       st->codec->bit_rate     = bitrate > 0 ? bitrate : 145*1000000;\r
+                       st->codec->width        = std::min<size_t>(1280, format_desc_.width);\r
+                       st->codec->height       = std::min<size_t>(720, format_desc_.height);\r
+                       st->codec->pix_fmt      = PIX_FMT_YUV422P;\r
+               }\r
+               else\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("unsupported codec"));\r
+               \r
+               if(oc_->oformat->flags & AVFMT_GLOBALHEADER)\r
                        st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;\r
 \r
                auto codec = avcodec_find_encoder(st->codec->codec_id);\r
@@ -181,7 +201,7 @@ public:
                });\r
        }\r
        \r
-       std::shared_ptr<AVStream> add_audio_stream(enum CodecID codec_id)\r
+       std::shared_ptr<AVStream> add_audio_stream()\r
        {\r
                auto st = av_new_stream(oc_.get(), 1);\r
                if (!st) \r
@@ -196,8 +216,8 @@ public:
                st->codec->sample_rate  = 48000;\r
                st->codec->channels             = 2;\r
                st->codec->sample_fmt   = SAMPLE_FMT_S16;\r
-               
-               if(oc_->oformat->flags & AVFMT_GLOBALHEADER)
+               \r
+               if(oc_->oformat->flags & AVFMT_GLOBALHEADER)\r
                        st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;\r
                \r
                auto codec = avcodec_find_encoder(st->codec->codec_id);\r
@@ -287,21 +307,27 @@ public:
 \r
 struct ffmpeg_consumer_proxy : public core::frame_consumer\r
 {\r
-       const std::wstring filename_;\r
-       const bool key_only_;\r
+       const std::wstring      filename_;\r
+       const bool                      key_only_;\r
+       const std::string       codec_;\r
+       const int                       bitrate_;\r
 \r
        std::unique_ptr<ffmpeg_consumer> consumer_;\r
 \r
 public:\r
 \r
-       ffmpeg_consumer_proxy(const std::wstring& filename, bool key_only)\r
+       ffmpeg_consumer_proxy(const std::wstring& filename, bool key_only, const std::string codec, int bitrate)\r
                : filename_(filename)\r
-               , key_only_(key_only){}\r
+               , key_only_(key_only)\r
+               , codec_(boost::to_lower_copy(codec))\r
+               , bitrate_(bitrate)\r
+       {\r
+       }\r
        \r
        virtual void initialize(const core::video_format_desc& format_desc, int, int)\r
        {\r
                consumer_.reset();\r
-               consumer_.reset(new ffmpeg_consumer(narrow(filename_), format_desc));\r
+               consumer_.reset(new ffmpeg_consumer(narrow(filename_), format_desc, codec_, bitrate_));\r
        }\r
        \r
        virtual bool send(const safe_ptr<core::read_frame>& frame) override\r
@@ -335,15 +361,27 @@ safe_ptr<core::frame_consumer> create_ffmpeg_consumer(const std::vector<std::wst
        boost::filesystem::remove(boost::filesystem::wpath(env::media_folder() + params[1])); // Delete the file if it exists\r
        bool key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();\r
 \r
-       return make_safe<ffmpeg_consumer_proxy>(env::media_folder() + params[1], key_only);\r
+       std::string codec = "dnxhd";\r
+       auto codec_it = std::find(params.begin(), params.end(), L"CODEC");\r
+       if(codec_it++ != params.end())\r
+               codec = narrow(*codec_it);\r
+\r
+       int bitrate = 0;        \r
+       auto bitrate_it = std::find(params.begin(), params.end(), L"BITRATE");\r
+       if(bitrate_it++ != params.end())\r
+               bitrate = boost::lexical_cast<int>(*codec_it);\r
+\r
+       return make_safe<ffmpeg_consumer_proxy>(env::media_folder() + params[1], key_only, codec, bitrate);\r
 }\r
 \r
 safe_ptr<core::frame_consumer> create_ffmpeg_consumer(const boost::property_tree::ptree& ptree)\r
 {\r
        std::string filename = ptree.get<std::string>("path");\r
-       bool key_only            = ptree.get("key-only", false);\r
+       auto key_only            = ptree.get("key-only", false);\r
+       auto codec                       = ptree.get("codec", "dnxhd");\r
+       auto bitrate             = ptree.get("bitrate", 0);\r
        \r
-       return make_safe<ffmpeg_consumer_proxy>(env::media_folder() + widen(filename), key_only);\r
+       return make_safe<ffmpeg_consumer_proxy>(env::media_folder() + widen(filename), key_only, codec, bitrate);\r
 }\r
 \r
 }}\r