]> git.sesse.net Git - casparcg/commitdiff
2.0.2: ffmpeg_consumer: Added support for DVCPRO and DNXHD. Added multithreading...
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Thu, 1 Dec 2011 01:06:09 +0000 (01:06 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Thu, 1 Dec 2011 01:06:09 +0000 (01:06 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.2@1742 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

core/consumer/output.cpp
modules/ffmpeg/consumer/ffmpeg_consumer.cpp

index 946ed890b66f323cf2053873a2dc80b55112c4b9..a28702c266fe8104e44a76e3742a69ebf3bc9e99 100644 (file)
@@ -115,6 +115,7 @@ public:
                                catch(...)\r
                                {\r
                                        CASPAR_LOG_CURRENT_EXCEPTION();\r
+                                       CASPAR_LOG(info) << print() << L" " << it->second->print() << L" Removed.";\r
                                        consumers_.erase(it++);\r
                                }\r
                        }\r
@@ -180,7 +181,10 @@ public:
                                                if(consumer->send(frame))\r
                                                        ++it;\r
                                                else\r
+                                               {\r
+                                                       CASPAR_LOG(info) << print() << L" " << it->second->print() << L" Removed.";\r
                                                        consumers_.erase(it++);\r
+                                               }\r
                                        }\r
                                        catch(...)\r
                                        {\r
index 6f8505a55a895663001a58bb737d368f5f34acb3..b5845fc5921311aa72dfd0819f9315c81a96cb04 100644 (file)
@@ -21,7 +21,6 @@
 #include "../StdAfx.h"\r
 \r
 #include "../ffmpeg_error.h"\r
-#include "../producer/tbb_avcodec.h"\r
 \r
 #include "ffmpeg_consumer.h"\r
 \r
 #include <core/video_format.h>\r
 \r
 #include <common/concurrency/executor.h>\r
+#include <common/diagnostics/graph.h>\r
 #include <common/utility/string.h>\r
 #include <common/env.h>\r
 \r
+#include <boost/timer.hpp>\r
 #include <boost/thread/once.hpp>\r
+#include <boost/thread.hpp>\r
 #include <boost/algorithm/string.hpp>\r
 \r
 #include <tbb/cache_aligned_allocator.h>\r
@@ -66,7 +68,12 @@ struct ffmpeg_consumer : boost::noncopyable
        const std::shared_ptr<AVFormatContext>  oc_;\r
        const core::video_format_desc                   format_desc_;\r
        \r
+       const safe_ptr<diagnostics::graph>              graph_;\r
+       boost::timer                                                    frame_timer_;\r
+       boost::timer                                                    write_timer_;\r
+\r
        executor                                                                executor_;\r
+       executor                                                                file_write_executor_;\r
 \r
        // Audio\r
        std::shared_ptr<AVStream>                               audio_st_;\r
@@ -89,9 +96,17 @@ public:
                , oc_(avformat_alloc_context(), av_free)\r
                , format_desc_(format_desc)\r
                , executor_(print())\r
+               , file_write_executor_(print() + L"/output")\r
        {\r
-               executor_.set_capacity(25);\r
-               \r
+               graph_->add_guide("frame-time", 0.5);\r
+               graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));\r
+               graph_->set_color("write-time", diagnostics::color(0.5f, 0.5f, 0.1f));\r
+               graph_->set_text(print());\r
+               diagnostics::register_graph(graph_);\r
+\r
+               executor_.set_capacity(8);\r
+               file_write_executor_.set_capacity(8);\r
+\r
                oc_->oformat = av_guess_format(nullptr, filename_.c_str(), nullptr);\r
                if (!oc_->oformat)\r
                        BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Could not find suitable output format."));\r
@@ -121,6 +136,9 @@ public:
 \r
        ~ffmpeg_consumer()\r
        {    \r
+               file_write_executor_.stop();\r
+               file_write_executor_.join();\r
+\r
                executor_.stop();\r
                executor_.join();\r
                \r
@@ -163,8 +181,11 @@ public:
                                << msg_info("Could not alloc video-stream")                             \r
                                << boost::errinfo_api_function("av_new_stream"));\r
                }\r
+\r
+               bitrate *= 1000000;\r
                \r
                st->codec->codec_id                     = codec_id;\r
+               st->codec->bit_rate                     = bitrate > 0 ? bitrate : format_desc_.width < 1280 ? 42*1000000 : 147*1000000;\r
                st->codec->codec_type           = AVMEDIA_TYPE_VIDEO;\r
                st->codec->width                        = format_desc_.width;\r
                st->codec->height                       = format_desc_.height;\r
@@ -178,11 +199,28 @@ public:
                }\r
                else if(st->codec->codec_id == CODEC_ID_DNXHD)\r
                {\r
+                       if(format_desc_.width < 1280 || format_desc_.height < 720)\r
+                               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("unsupported dimension"));\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
+               }\r
+               else if(st->codec->codec_id == CODEC_ID_DVVIDEO)\r
+               {\r
+                       st->codec->bit_rate     = bitrate > 0 ? bitrate : format_desc_.width < 1280 ? 50*1000000 : 100*1000000;\r
                        st->codec->pix_fmt      = PIX_FMT_YUV422P;\r
                }\r
+               //else if(st->codec->codec_id == CODEC_ID_H264)\r
+               //{                     \r
+               //      st->codec->pix_fmt              = PIX_FMT_YUV422P;\r
+               //      st->codec->me_range             = 16;\r
+               //      st->codec->max_qdiff    = 4;\r
+               //      st->codec->qmin                 = 10;\r
+               //      st->codec->qmax                 = 51;\r
+               //      st->codec->qcompress    = 0.6;\r
+               //      st->codec->gop_size             = 25;\r
+               //}\r
                else\r
                        BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("unsupported codec"));\r
                \r
@@ -193,11 +231,12 @@ public:
                if (!codec)\r
                        BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("codec not found"));\r
 \r
-               THROW_ON_ERROR2(tbb_avcodec_open(st->codec, codec), "[ffmpeg_consumer]");\r
+               st->codec->thread_count = boost::thread::hardware_concurrency();\r
+               THROW_ON_ERROR2(avcodec_open(st->codec, codec), "[ffmpeg_consumer]");\r
 \r
                return std::shared_ptr<AVStream>(st, [](AVStream* st)\r
                {\r
-                       tbb_avcodec_close(st->codec);\r
+                       avcodec_close(st->codec);\r
                });\r
        }\r
        \r
@@ -211,11 +250,11 @@ public:
                                << boost::errinfo_api_function("av_new_stream"));\r
                }\r
 \r
-               st->codec->codec_id             = CODEC_ID_PCM_S16LE;\r
-               st->codec->codec_type   = AVMEDIA_TYPE_AUDIO;\r
-               st->codec->sample_rate  = 48000;\r
-               st->codec->channels             = 2;\r
-               st->codec->sample_fmt   = SAMPLE_FMT_S16;\r
+               st->codec->codec_id                     = CODEC_ID_PCM_S16LE;\r
+               st->codec->codec_type           = AVMEDIA_TYPE_AUDIO;\r
+               st->codec->sample_rate          = 48000;\r
+               st->codec->channels                     = 2;\r
+               st->codec->sample_fmt           = SAMPLE_FMT_S16;\r
                \r
                if(oc_->oformat->flags & AVFMT_GLOBALHEADER)\r
                        st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;\r
@@ -232,7 +271,7 @@ public:
                });\r
        }\r
   \r
-       void encode_video_frame(const safe_ptr<core::read_frame>& frame)\r
+       std::shared_ptr<AVPacket> encode_video_frame(const safe_ptr<core::read_frame>& frame)\r
        { \r
                auto c = video_st_->codec;\r
  \r
@@ -258,49 +297,72 @@ public:
                int out_size = THROW_ON_ERROR2(avcodec_encode_video(c, video_outbuf_.data(), video_outbuf_.size(), local_av_frame.get()), "[ffmpeg_consumer]");\r
                if(out_size > 0)\r
                {\r
-                       AVPacket pkt;\r
-                       av_init_packet(&pkt);\r
+                       safe_ptr<AVPacket> pkt(new AVPacket, [](AVPacket* p)\r
+                       {\r
+                               av_free_packet(p);\r
+                               delete p;\r
+                       });\r
+                       av_init_packet(pkt.get());\r
  \r
                        if (c->coded_frame->pts != AV_NOPTS_VALUE)\r
-                               pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, video_st_->time_base);\r
+                               pkt->pts = av_rescale_q(c->coded_frame->pts, c->time_base, video_st_->time_base);\r
 \r
                        if(c->coded_frame->key_frame)\r
-                               pkt.flags |= AV_PKT_FLAG_KEY;\r
+                               pkt->flags |= AV_PKT_FLAG_KEY;\r
 \r
-                       pkt.stream_index        = video_st_->index;\r
-                       pkt.data                        = video_outbuf_.data();\r
-                       pkt.size                        = out_size;\r
+                       pkt->stream_index       = video_st_->index;\r
+                       pkt->data                       = video_outbuf_.data();\r
+                       pkt->size                       = out_size;\r
  \r
-                       THROW_ON_ERROR2(av_interleaved_write_frame(oc_.get(), &pkt), L"[ffmpeg_consumer]");\r
+                       av_dup_packet(pkt.get());\r
+                       return pkt;\r
                }       \r
+               return nullptr;\r
        }\r
                \r
-       void encode_audio_frame(const safe_ptr<core::read_frame>& frame)\r
+       std::shared_ptr<AVPacket> encode_audio_frame(const safe_ptr<core::read_frame>& frame)\r
        {                       \r
                auto c = audio_st_->codec;\r
 \r
                auto audio_data = core::audio_32_to_16(frame->audio_data());\r
-\r
-               AVPacket pkt;\r
-               av_init_packet(&pkt);\r
+               \r
+               safe_ptr<AVPacket> pkt(new AVPacket, [](AVPacket* p)\r
+               {\r
+                       av_free_packet(p);\r
+                       delete p;\r
+               });\r
+               av_init_packet(pkt.get());\r
                \r
                if (c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE)\r
-                       pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, audio_st_->time_base);\r
+                       pkt->pts = av_rescale_q(c->coded_frame->pts, c->time_base, audio_st_->time_base);\r
 \r
-               pkt.flags                |= AV_PKT_FLAG_KEY;\r
-               pkt.stream_index = audio_st_->index;\r
-               pkt.size                 = audio_data.size()*2;\r
-               pkt.data                 = reinterpret_cast<uint8_t*>(audio_data.data());\r
+               pkt->flags               |= AV_PKT_FLAG_KEY;\r
+               pkt->stream_index = audio_st_->index;\r
+               pkt->size                = audio_data.size()*2;\r
+               pkt->data                = reinterpret_cast<uint8_t*>(audio_data.data());\r
                \r
-               THROW_ON_ERROR2(av_interleaved_write_frame(oc_.get(), &pkt), L"[ffmpeg_consumer]");\r
+               av_dup_packet(pkt.get());\r
+               return pkt;\r
        }\r
                 \r
        void send(const safe_ptr<core::read_frame>& frame)\r
        {\r
                executor_.begin_invoke([=]\r
-               {                               \r
-                       encode_video_frame(frame);\r
-                       encode_audio_frame(frame);\r
+               {               \r
+                       frame_timer_.restart();\r
+                       auto video = encode_video_frame(frame);\r
+                       auto audio = encode_audio_frame(frame);\r
+                       graph_->update_value("frame-time", frame_timer_.elapsed()*format_desc_.fps*0.5);\r
+                       \r
+                       file_write_executor_.begin_invoke([=]\r
+                       {\r
+                               write_timer_.restart();\r
+                               if(video)\r
+                                       av_write_frame(oc_.get(), video.get());\r
+                               if(audio)\r
+                                       av_write_frame(oc_.get(), audio.get());\r
+                               graph_->update_value("write-time", write_timer_.elapsed()*format_desc_.fps*0.5);\r
+                       });\r
                });\r
        }\r
 };\r
@@ -363,13 +425,13 @@ safe_ptr<core::frame_consumer> create_ffmpeg_consumer(const std::vector<std::wst
 \r
        std::string codec = "dnxhd";\r
        auto codec_it = std::find(params.begin(), params.end(), L"CODEC");\r
-       if(codec_it++ != params.end())\r
+       if(codec_it != params.end() && 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
+       if(bitrate_it != params.end() && bitrate_it++ != params.end())\r
+               bitrate = boost::lexical_cast<int>(*bitrate_it);\r
 \r
        return make_safe<ffmpeg_consumer_proxy>(env::media_folder() + params[1], key_only, codec, bitrate);\r
 }\r