From: ronag Date: Thu, 11 Nov 2010 21:52:49 +0000 (+0000) Subject: 2.0.0.2: X-Git-Tag: 2.0.1~943 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=d7eb87d99d5780c8aca85ec7659313761de538f3;p=casparcg 2.0.0.2: - FFMPEG updated audio decoding. - Refactorin. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@244 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- diff --git a/common/common.vcxproj b/common/common.vcxproj index 98febc51d..31d3b0162 100644 --- a/common/common.vcxproj +++ b/common/common.vcxproj @@ -80,7 +80,7 @@ AnySuitable Speed true - false + true true diff --git a/core/channel.h b/core/channel.h index 2e89bc6bc..01ed86031 100644 --- a/core/channel.h +++ b/core/channel.h @@ -16,8 +16,8 @@ namespace caspar { namespace core { /// \brief Channel. /// /// |**********| <- empty frame <- |***********| <- frame format <- |**********| -/// CONTROLLER -> | PRODUCER | | PROCESSOR | | CONSUMER | -> DISPLAY DEVICE -/// |**********| -> rendered frames -> |***********| -> processed frame -> |**********| +/// PROTOCOL -> | PRODUCER | | PROCESSOR | | CONSUMER | -> DISPLAY DEVICE +/// |**********| -> rendered frames -> |***********| -> formatted frame -> |**********| /// //////////////////////////////////////////////////////////////////////////////////////////////////// class channel : boost::noncopyable diff --git a/core/consumer/bluefish/bluefish_consumer.h b/core/consumer/bluefish/bluefish_consumer.h index 3374a3064..081df147b 100644 --- a/core/consumer/bluefish/bluefish_consumer.h +++ b/core/consumer/bluefish/bluefish_consumer.h @@ -19,7 +19,7 @@ */ #pragma once -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include "../../consumer/frame_consumer.h" namespace caspar { namespace core { namespace bluefish { diff --git a/core/consumer/bluefish/memory.h b/core/consumer/bluefish/memory.h index 18856d046..af39c7a3a 100644 --- a/core/consumer/bluefish/memory.h +++ b/core/consumer/bluefish/memory.h @@ -3,7 +3,7 @@ #include #include -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include "exception.h" namespace caspar { namespace core { namespace bluefish { diff --git a/core/consumer/bluefish/util.h b/core/consumer/bluefish/util.h index 6c8eddbf6..b2e3367b4 100644 --- a/core/consumer/bluefish/util.h +++ b/core/consumer/bluefish/util.h @@ -1,7 +1,7 @@ #pragma once #include -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include diff --git a/core/consumer/decklink/DecklinkVideoConsumer.cpp b/core/consumer/decklink/DecklinkVideoConsumer.cpp index 01589fda9..ea13ab91c 100644 --- a/core/consumer/decklink/DecklinkVideoConsumer.cpp +++ b/core/consumer/decklink/DecklinkVideoConsumer.cpp @@ -28,7 +28,7 @@ #include "DecklinkVideoConsumer.h" #include "DeckLinkAPI_h.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include "../../../common/utility/memory.h" #include "../../producer/frame_producer_device.h" diff --git a/core/consumer/decklink/DecklinkVideoConsumer.h b/core/consumer/decklink/DecklinkVideoConsumer.h index b0da679df..ab6e1411b 100644 --- a/core/consumer/decklink/DecklinkVideoConsumer.h +++ b/core/consumer/decklink/DecklinkVideoConsumer.h @@ -21,7 +21,7 @@ #include "../../consumer/frame_consumer.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" namespace caspar { namespace core { namespace decklink { diff --git a/core/consumer/frame_consumer.h b/core/consumer/frame_consumer.h index 632a895b4..47de96aaf 100644 --- a/core/consumer/frame_consumer.h +++ b/core/consumer/frame_consumer.h @@ -19,7 +19,7 @@ */ #pragma once -#include "../video/video_format.h" +#include "../format/video_format.h" #include "../processor/frame.h" #include diff --git a/core/consumer/frame_consumer_device.cpp b/core/consumer/frame_consumer_device.cpp index 4d311eb7b..b130cb151 100644 --- a/core/consumer/frame_consumer_device.cpp +++ b/core/consumer/frame_consumer_device.cpp @@ -6,7 +6,7 @@ #include "frame_consumer_device.h" -#include "../video/video_format.h" +#include "../format/video_format.h" #include "../processor/frame.h" #include "../processor/frame_processor_device.h" @@ -86,12 +86,9 @@ public: clock.synchronize(); frame_ptr frame; - while(frame == nullptr && !frame_processor_->try_receive(frame)) - { - if(frame != nullptr) - CASPAR_LOG(trace) << "Display Buffer Underrun."; + while(frame == nullptr && is_running_) frame_processor_->receive(frame); - } + display_frame(frame); } diff --git a/core/consumer/oal/oal_consumer.cpp b/core/consumer/oal/oal_consumer.cpp index 6fd9ccb61..fa14210bb 100644 --- a/core/consumer/oal/oal_consumer.cpp +++ b/core/consumer/oal/oal_consumer.cpp @@ -23,7 +23,7 @@ #include "oal_consumer.h" #include "../../processor/frame.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include diff --git a/core/consumer/ogl/ogl_consumer.cpp b/core/consumer/ogl/ogl_consumer.cpp index f58373caa..d0c644fd0 100644 --- a/core/consumer/ogl/ogl_consumer.cpp +++ b/core/consumer/ogl/ogl_consumer.cpp @@ -22,7 +22,7 @@ #include "ogl_consumer.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include "../../processor/frame.h" #include "../../../common/utility/memory.h" #include "../../../common/gl/utility.h" diff --git a/core/core.vcxproj b/core/core.vcxproj index 1f73531bd..713a2651e 100644 --- a/core/core.vcxproj +++ b/core/core.vcxproj @@ -118,7 +118,7 @@ ProgramDatabase true NDEBUG;_VC80_UPGRADE=0x0710;%(PreprocessorDefinitions) - false + true true @@ -164,6 +164,8 @@ + + @@ -200,8 +202,6 @@ - - @@ -235,6 +235,10 @@ ../../StdAfx.h ../../StdAfx.h + + ../StdAfx.h + ../StdAfx.h + ../StdAfx.h ../StdAfx.h @@ -367,10 +371,6 @@ Create Create - - ../StdAfx.h - ../StdAfx.h - diff --git a/core/core.vcxproj.filters b/core/core.vcxproj.filters index f3ef8dbe6..ecec160e2 100644 --- a/core/core.vcxproj.filters +++ b/core/core.vcxproj.filters @@ -4,6 +4,24 @@ {0361bd88-1d96-4d86-b3ad-34d40e2319c6} + + {57f477cb-9cff-4216-aab7-50b06df51f20} + + + {a94bc00a-4753-4bce-a777-6a3ea2ceca59} + + + {d33e8ddc-ccb4-4f4f-ad20-e788a796bb7b} + + + {8355a891-c4db-4a0e-8ecc-795314127cdc} + + + {23166bfa-06eb-4da9-8a0d-1ae5eac4348b} + + + {bb801cd9-8dc8-4300-a5c7-a7f5ee0805fb} + {35d7835f-f813-4b4b-8d8d-8a35dfef68d3} @@ -22,12 +40,27 @@ {a5cb89d7-dbbb-4fca-b899-f53a069727b4} + + {f19ced4f-4ad2-4c0a-b51f-50e89909d669} + + + {53e41831-70b4-4214-bc38-77e0d7aa288b} + + + {30fe40ca-8bf0-4a46-a882-16d07b2b441e} + {71accefc-1437-4e1d-9ff7-9de654a32df9} {671d13be-c7e1-4f65-9909-03b7c8adcbde} + + {a6d6bcc9-7ef1-47a3-9800-76e71f2b3f62} + + + {4031dc0c-88e9-46b5-b279-955639dca8b7} + {78b16c14-bf29-4511-9122-684ff513dbf5} @@ -37,44 +70,11 @@ {fc25232a-cab1-4c79-962a-b51dc51161fb} - - {3d4314f3-8a39-44e3-a0c9-9b833bb8f809} - - - {a6d6bcc9-7ef1-47a3-9800-76e71f2b3f62} - - - {4031dc0c-88e9-46b5-b279-955639dca8b7} - {f99e4727-2b1b-4009-a445-99b11b071e8e} - - {57f477cb-9cff-4216-aab7-50b06df51f20} - - - {a94bc00a-4753-4bce-a777-6a3ea2ceca59} - - - {d33e8ddc-ccb4-4f4f-ad20-e788a796bb7b} - - - {8355a891-c4db-4a0e-8ecc-795314127cdc} - - - {23166bfa-06eb-4da9-8a0d-1ae5eac4348b} - - - {bb801cd9-8dc8-4300-a5c7-a7f5ee0805fb} - - - {f19ced4f-4ad2-4c0a-b51f-50e89909d669} - - - {53e41831-70b4-4214-bc38-77e0d7aa288b} - - - {30fe40ca-8bf0-4a46-a882-16d07b2b441e} + + {3d4314f3-8a39-44e3-a0c9-9b833bb8f809} @@ -201,12 +201,6 @@ Source\producer - - Source\video - - - Source\video - Source\consumer @@ -216,9 +210,6 @@ Source - - Source - Source\processor @@ -234,6 +225,15 @@ Source\processor\renderer + + Source\format + + + Source\format + + + Source + @@ -329,9 +329,6 @@ Source\producer - - Source\video - Source\consumer @@ -356,6 +353,9 @@ Source\processor\renderer + + Source\format + Source diff --git a/core/format/pixel_format.h b/core/format/pixel_format.h new file mode 100644 index 000000000..2bf7372a6 --- /dev/null +++ b/core/format/pixel_format.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +namespace caspar { namespace core { + +struct pixel_format +{ + enum type + { + bgra, + rgba, + argb, + abgr, + ycbcr, + ycbcra, + count, + invalid + }; +}; + +struct pixel_format_desc +{ + struct plane + { + plane() : linesize(0), width(0), height(0), size(0), channels(0){} + plane(size_t width, size_t height, size_t channels) + : linesize(width*channels), width(width), height(height), size(width*height*channels), channels(channels) + {} + size_t linesize; + size_t width; + size_t height; + size_t size; + size_t channels; + }; + + pixel_format_desc() : pix_fmt(pixel_format::invalid) + { + std::fill(planes.begin(), planes.end(), plane()); + } + + pixel_format::type pix_fmt; + + std::array planes; +}; + +}} \ No newline at end of file diff --git a/core/format/video_format.cpp b/core/format/video_format.cpp new file mode 100644 index 000000000..73f839e74 --- /dev/null +++ b/core/format/video_format.cpp @@ -0,0 +1,62 @@ +/* +* copyright (c) 2010 Sveriges Television AB +* +* This file is part of CasparCG. +* +* CasparCG is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* CasparCG is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with CasparCG. If not, see . +* +*/ + +#include "..\StdAfx.h" + +#include "video_format.h" + +#include + +#define DEFINE_VIDEOFORMATDESC(w, h, m, f, s, fmt) { (fmt), (w), (h), (m), (f), (w)*(h)*4, (s) } + +namespace caspar { namespace core { + +const video_format_desc video_format_desc::format_descs[video_format::count] = +{ + DEFINE_VIDEOFORMATDESC(720, 576, video_update_format::upper, 50, TEXT("PAL"), video_format::pal ), + DEFINE_VIDEOFORMATDESC(720, 486, video_update_format::lower, 60/1.001, TEXT("NTSC"), video_format::ntsc ), + DEFINE_VIDEOFORMATDESC(720, 576, video_update_format::progressive, 25, TEXT("576p2500"), video_format::x576p2500 ), + DEFINE_VIDEOFORMATDESC(1280, 720, video_update_format::progressive, 25, TEXT("720p2500"), video_format::x720p2500 ), + DEFINE_VIDEOFORMATDESC(1280, 720, video_update_format::progressive, 50, TEXT("720p5000"), video_format::x720p5000 ), + DEFINE_VIDEOFORMATDESC(1280, 720, video_update_format::progressive, 60/1.001, TEXT("720p5994"), video_format::x720p5994 ), + DEFINE_VIDEOFORMATDESC(1280, 720, video_update_format::progressive, 60, TEXT("720p6000"), video_format::x720p6000 ), + DEFINE_VIDEOFORMATDESC(1920, 1080, video_update_format::progressive, 24/1.001, TEXT("1080p2397"), video_format::x1080p2397), + DEFINE_VIDEOFORMATDESC(1920, 1080, video_update_format::progressive, 24, TEXT("1080p2400"), video_format::x1080p2400), + DEFINE_VIDEOFORMATDESC(1920, 1080, video_update_format::upper, 50, TEXT("1080i5000"), video_format::x1080i5000), + DEFINE_VIDEOFORMATDESC(1920, 1080, video_update_format::upper, 60/1.001, TEXT("1080i5994"), video_format::x1080i5994), + DEFINE_VIDEOFORMATDESC(1920, 1080, video_update_format::upper, 60, TEXT("1080i6000"), video_format::x1080i6000), + DEFINE_VIDEOFORMATDESC(1920, 1080, video_update_format::progressive, 25, TEXT("1080p2500"), video_format::x1080p2500), + DEFINE_VIDEOFORMATDESC(1920, 1080, video_update_format::progressive, 30/1.001, TEXT("1080p2997"), video_format::x1080p2997), + DEFINE_VIDEOFORMATDESC(1920, 1080, video_update_format:: progressive, 30, TEXT("1080p3000"), video_format::x1080p3000) +}; + +video_format::type get_video_format(const std::wstring& name) +{ + for(int n = 0; n < video_format::count; ++n) + { + if(boost::iequals(video_format_desc::format_descs[n].name, name)) + return static_cast(n); + } + + return video_format::invalid; +} + +}} + diff --git a/core/format/video_format.h b/core/format/video_format.h new file mode 100644 index 000000000..efa1b239e --- /dev/null +++ b/core/format/video_format.h @@ -0,0 +1,120 @@ +#pragma once + +#include + +#include "../../common/compiler/vs/disable_silly_warnings.h" + +namespace caspar { namespace core { + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// \enum video_format +/// +//////////////////////////////////////////////////////////////////////////////////////////////////// +struct video_format +{ + enum type + { + pal = 0, + ntsc, + x576p2500, + x720p2500, + x720p5000, + x720p5994, + x720p6000, + x1080p2397, + x1080p2400, + x1080i5000, + x1080i5994, + x1080i6000, + x1080p2500, + x1080p2997, + x1080p3000, + count, + invalid + }; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// \enum video_update_format +/// +//////////////////////////////////////////////////////////////////////////////////////////////////// +struct video_update_format +{ + enum type + { + progressive, + lower, + upper, + count, + invalid + }; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// \struct video_format_desc +/// +//////////////////////////////////////////////////////////////////////////////////////////////////// +struct video_format_desc +{ + video_format::type format; + + size_t width; + size_t height; + video_update_format::type update; + double fps; + size_t size; + std::wstring name; + + static const video_format_desc format_descs[video_format::count]; +}; + +inline bool operator==(const video_format_desc& rhs, const video_format_desc& lhs) +{ + return rhs.format == lhs.format; +} + +inline bool operator!=(const video_format_desc& rhs, const video_format_desc& lhs) +{ + return !(rhs == lhs); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// \fn video_format get_video_format(const std::wstring& strVideoMode); +/// +/// \brief Gets the *video_format* associated with the specified name. +/// +/// \param name Name of the *video_format*.. +/// +/// \return The video format. +//////////////////////////////////////////////////////////////////////////////////////////////////// +video_format::type get_video_format(const std::wstring& name); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// \fn video_format get_video_format_desc(const std::wstring& strVideoMode); +/// +/// \brief Gets the *video_format_desc* associated with the specified name. +/// +/// \param name Name of the *video_format_desc*.. +/// +/// \return The video format. +//////////////////////////////////////////////////////////////////////////////////////////////////// +inline video_format_desc get_video_format_desc(const std::wstring& name, video_format::type default_format = video_format::x576p2500) +{ + auto casparVideoFormat = default_format; + if(!name.empty()) + casparVideoFormat = get_video_format(name); + return video_format_desc::format_descs[casparVideoFormat]; +} + +inline double render_video_format_period(const video_format_desc& format_desc) +{ + return 1.0/(format_desc.update == video_update_format::progressive ? format_desc.fps : format_desc.fps/2.0); +} + +inline std::wostream& operator<<(std::wostream& out, const video_format_desc& format_desc) +{ + out << format_desc.name.c_str(); + return out; +} + +}} \ No newline at end of file diff --git a/core/processor/frame.cpp b/core/processor/frame.cpp index e1d089fd4..252fa2103 100644 --- a/core/processor/frame.cpp +++ b/core/processor/frame.cpp @@ -1,7 +1,7 @@ #include "../StdAfx.h" #include "frame.h" -#include "../video/pixel_format.h" +#include "../format/pixel_format.h" #include "../../common/utility/memory.h" #include "../../common/gl/utility.h" #include "../../common/gl/pixel_buffer_object.h" diff --git a/core/processor/frame.h b/core/processor/frame.h index aa6001e5e..223082b4f 100644 --- a/core/processor/frame.h +++ b/core/processor/frame.h @@ -2,8 +2,8 @@ #include "frame_shader.h" -#include "../video/video_format.h" -#include "../video/pixel_format.h" +#include "../format/video_format.h" +#include "../format/pixel_format.h" #include #include diff --git a/core/processor/frame_processor_device.cpp b/core/processor/frame_processor_device.cpp index ea3d2237b..bf746e920 100644 --- a/core/processor/frame_processor_device.cpp +++ b/core/processor/frame_processor_device.cpp @@ -6,7 +6,7 @@ #include "frame.h" #include "composite_frame.h" -#include "../video/video_format.h" +#include "../format/video_format.h" #include "../../common/exception/exceptions.h" #include "../../common/concurrency/executor.h" @@ -29,7 +29,7 @@ namespace caspar { namespace core { struct frame_processor_device::implementation : boost::noncopyable { implementation(frame_processor_device* self, const video_format_desc& format_desc) - : fmt_(format_desc) + : fmt_(format_desc), underrun_count_(0) { boost::promise promise; active_frame_ = promise.get_future(); @@ -93,14 +93,15 @@ struct frame_processor_device::implementation : boost::noncopyable void send(const frame_ptr& input_frame) { - input_.push(input_frame); + input_.push(input_frame); // Block if there are too many frames in pipeline executor_.begin_invoke([=] { try { frame_ptr output_frame; input_.pop(output_frame); - output_.push(renderer_->render(output_frame)); + if(output_frame != nullptr) + output_.push(renderer_->render(output_frame)); } catch(...) { @@ -111,14 +112,21 @@ struct frame_processor_device::implementation : boost::noncopyable void receive(frame_ptr& output_frame) { - output_.pop(output_frame); + if(!output_.try_pop(output_frame)) + { + if(underrun_count_ == 0) + CASPAR_LOG(trace) << "Frame Processor Underrun has STARTED."; + + ++underrun_count_; + output_.pop(output_frame); + } + else if(underrun_count_ > 0) + { + CASPAR_LOG(trace) << "Frame Processor Underrun has ENDED with " << underrun_count_ << " ticks."; + underrun_count_ = 0; + } } - bool try_receive(frame_ptr& output_frame) - { - return output_.try_pop(output_frame); - } - video_format_desc fmt_; typedef tbb::concurrent_bounded_queue frame_queue; @@ -135,6 +143,8 @@ struct frame_processor_device::implementation : boost::noncopyable frame_queue output_; frame_renderer_ptr renderer_; + + long underrun_count_; }; #if defined(_MSC_VER) @@ -147,7 +157,6 @@ frame_ptr frame_processor_device::create_frame(const pixel_format_desc& desc, v void frame_processor_device::release_tag(void* tag){impl_->release_tag(tag);} void frame_processor_device::send(const frame_ptr& frame){impl_->send(frame);} void frame_processor_device::receive(frame_ptr& frame){impl_->receive(frame);} -bool frame_processor_device::try_receive(frame_ptr& frame){return impl_->try_receive(frame);} const video_format_desc frame_processor_device::get_video_format_desc() const { return impl_->fmt_;} frame_ptr frame_processor_device::create_frame(size_t width, size_t height, void* tag) { diff --git a/core/processor/frame_processor_device.h b/core/processor/frame_processor_device.h index 91b1ae60a..1fb115ec2 100644 --- a/core/processor/frame_processor_device.h +++ b/core/processor/frame_processor_device.h @@ -22,7 +22,7 @@ #include #include -#include "../video/video_format.h" +#include "../format/video_format.h" #include "../processor/frame.h" #include "../consumer/frame_consumer_device.h" @@ -35,7 +35,6 @@ public: void send(const frame_ptr& frame); void receive(frame_ptr& frame); - bool try_receive(frame_ptr& frame); frame_ptr create_frame(const pixel_format_desc& desc, void* tag); frame_ptr create_frame(size_t width, size_t height, void* tag); diff --git a/core/processor/frame_renderer.cpp b/core/processor/frame_renderer.cpp index c17e34146..772beb3d0 100644 --- a/core/processor/frame_renderer.cpp +++ b/core/processor/frame_renderer.cpp @@ -4,7 +4,7 @@ #include "../processor/frame.h" -#include "../video/video_format.h" +#include "../format/video_format.h" #include "../processor/frame_processor_device.h" #include "../../common/exception/exceptions.h" diff --git a/core/processor/frame_renderer.h b/core/processor/frame_renderer.h index ef314c39a..127697825 100644 --- a/core/processor/frame_renderer.h +++ b/core/processor/frame_renderer.h @@ -21,7 +21,7 @@ #include "frame_processor_device.h" -#include "../video/video_format.h" +#include "../format/video_format.h" #include diff --git a/core/processor/frame_shader.h b/core/processor/frame_shader.h index 64fd493c0..f31d88d1e 100644 --- a/core/processor/frame_shader.h +++ b/core/processor/frame_shader.h @@ -1,7 +1,7 @@ #pragma once -#include "../video/video_format.h" -#include "../video/pixel_format.h" +#include "../format/video_format.h" +#include "../format/pixel_format.h" #include #include diff --git a/core/producer/color/color_producer.cpp b/core/producer/color/color_producer.cpp index 4fcdb7e4b..7a244ce6e 100644 --- a/core/producer/color/color_producer.cpp +++ b/core/producer/color/color_producer.cpp @@ -22,7 +22,7 @@ #include "color_producer.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include #pragma intrinsic(__movsd, __stosd) diff --git a/core/producer/ffmpeg/audio/audio_decoder.cpp b/core/producer/ffmpeg/audio/audio_decoder.cpp index 753cfb5a2..d337a1c79 100644 --- a/core/producer/ffmpeg/audio/audio_decoder.cpp +++ b/core/producer/ffmpeg/audio/audio_decoder.cpp @@ -31,47 +31,89 @@ struct audio_decoder::implementation : boost::noncopyable static const int SAMPLE_RATE = 48000; implementation(AVCodecContext* codec_context) - : current_chunk_(), codec_context_(codec_context), audio_buffer_(4*SAMPLE_RATE*2+FF_INPUT_BUFFER_PADDING_SIZE/2){} + : current_chunk_(), codec_context_(codec_context), audio_resample_buffer_(4*SAMPLE_RATE*2+FF_INPUT_BUFFER_PADDING_SIZE/2), + audio_buffer_(4*SAMPLE_RATE*2+FF_INPUT_BUFFER_PADDING_SIZE/2)/*, resample_context_(nullptr)*/ + { + //if(codec_context_->sample_rate != SAMPLE_RATE) + //{ + // resample_context_ = av_audio_resample_init + // ( + // 2, + // codec_context_->channels, + // SAMPLE_RATE, // out rate + // codec_context_->sample_rate, // in rate + // SAMPLE_FMT_S16, + // codec_context_->sample_fmt, + // 16, 10, 0, 1.0 + // ); + //} + } + + ~implementation() + { + //if(resample_context_ != nullptr) + // audio_resample_close(resample_context_); + } std::vector> execute(const aligned_buffer& audio_packet) { - static std::vector> silence(1920*2, 0); - - if(codec_context_->sample_rate != SAMPLE_RATE) - return silence; - + static const std::vector> silence(1920*2, 0); + int written_bytes = audio_buffer_.size()*2 - FF_INPUT_BUFFER_PADDING_SIZE; - int result = avcodec_decode_audio2 - ( - codec_context_, - audio_buffer_.data(), - &written_bytes, - audio_packet.data(), - audio_packet.size() - ); + const int result = avcodec_decode_audio2(codec_context_, audio_buffer_.data(), &written_bytes, audio_packet.data(), audio_packet.size()); if(result <= 0) return silence; - - std::vector> chunks_; - - current_chunk_.insert(current_chunk_.end(), audio_buffer_.data(), audio_buffer_.data() + written_bytes/2); - while(current_chunk_.size() >= FRAME_AUDIO_SAMPLES) + + if(codec_context_->sample_rate != SAMPLE_RATE) { - auto first = std::make_move_iterator(current_chunk_.begin()); - auto last = std::make_move_iterator(current_chunk_.begin() + FRAME_AUDIO_SAMPLES); + //if(resample_context_ == nullptr) + return silence; + + //int samples_output = audio_resample + // ( + // resample_context_, + // audio_resample_buffer_.data(), + // audio_buffer_.data(), + // written_bytes/2 // in samples + // ); + + //if(samples_output == -1) + //{ + // CASPAR_LOG(trace) << "Resampling error"; + // audio_resample_close(resample_context_); + // resample_context_ = nullptr; + //} - chunks_.push_back(std::vector(first, last)); - current_chunk_ = std::vector(current_chunk_.begin() + FRAME_AUDIO_SAMPLES, current_chunk_.end()); + //current_chunk_.insert(current_chunk_.end(), audio_resample_buffer_.data(), audio_resample_buffer_.data() + samples_output); } + else + current_chunk_.insert(current_chunk_.end(), audio_buffer_.data(), audio_buffer_.data() + written_bytes/2); + + std::vector> chunks_; + + const auto last = current_chunk_.end() - current_chunk_.size() % FRAME_AUDIO_SAMPLES; + + for(auto it = current_chunk_.begin(); it != last; it += FRAME_AUDIO_SAMPLES) + chunks_.push_back(std::vector(it, it + FRAME_AUDIO_SAMPLES)); + + current_chunk_.erase(current_chunk_.begin(), last); return chunks_; } - - std::vector> audio_buffer_; - std::vector current_chunk_; - AVCodecContext* codec_context_; + //ReSampleContext* resample_context_; + + typedef std::vector> buffer; + + buffer audio_buffer_; + buffer audio_resample_buffer_; + + std::deque> current_chunk_; + + std::vector> current_resample_chunk_; + + AVCodecContext* codec_context_; }; audio_decoder::audio_decoder(AVCodecContext* codec_context) : impl_(new implementation(codec_context)){} diff --git a/core/producer/ffmpeg/ffmpeg_producer.cpp b/core/producer/ffmpeg/ffmpeg_producer.cpp index c9f66f14b..12b986388 100644 --- a/core/producer/ffmpeg/ffmpeg_producer.cpp +++ b/core/producer/ffmpeg/ffmpeg_producer.cpp @@ -27,7 +27,7 @@ extern "C" #include "video/video_decoder.h" #include "video/video_transformer.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include "../../../common/utility/find_file.h" #include "../../../common/utility/memory.h" #include "../../../common/utility/scope_exit.h" @@ -50,13 +50,16 @@ struct ffmpeg_producer : public frame_producer { public: ffmpeg_producer(const std::wstring& filename, const std::vector& params) - : filename_(filename) + : filename_(filename), underrun_count_(0) { if(!boost::filesystem::exists(filename)) BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(common::narrow(filename))); - static boost::once_flag flag = BOOST_ONCE_INIT; - boost::call_once(av_register_all, flag); + static boost::once_flag av_register_all_flag = BOOST_ONCE_INIT; + boost::call_once(av_register_all, av_register_all_flag); + + static boost::once_flag avcodec_init_flag = BOOST_ONCE_INIT; + boost::call_once(avcodec_init, avcodec_init_flag); input_.reset(new input()); input_->set_loop(std::find(params.begin(), params.end(), L"LOOP") != params.end()); @@ -84,11 +87,12 @@ public: frame_ptr render_frame() { while(ouput_channel_.empty() && !input_->is_eof()) - { + { + auto video_packet = input_->get_video_packet(); + auto audio_packet = input_->get_audio_packet(); tbb::parallel_invoke( [&] { // Video Decoding and Scaling - auto video_packet = input_->get_video_packet(); if(!video_packet.empty()) { auto decoded_frame = video_decoder_->execute(video_packet); @@ -98,7 +102,6 @@ public: }, [&] { // Audio Decoding - auto audio_packet = input_->get_audio_packet(); if(!audio_packet.empty()) { auto chunks = audio_decoder_->execute(audio_packet); @@ -106,9 +109,21 @@ public: } }); + if(video_packet.empty() && audio_packet.empty()) + { + if(underrun_count_ == 0) + CASPAR_LOG(warning) << "File read underflow has STARTED."; + ++underrun_count_; + } + else if(underrun_count_ > 0) + { + CASPAR_LOG(trace) << "File Read Underrun has ENDED with " << underrun_count_ << " ticks."; + underrun_count_ = 0; + } + while(!video_frame_channel_.empty() && (!audio_chunk_channel_.empty() || !has_audio_)) { - if(has_audio_) + if(has_audio_ && video_frame_channel_.front() != nullptr) { video_frame_channel_.front()->audio_data() = std::move(audio_chunk_channel_.front()); audio_chunk_channel_.pop_front(); @@ -131,23 +146,20 @@ public: bool has_audio_; - // Filter 1 : Input input_uptr input_; - // Filter 2 : Video Decoding and Scaling video_decoder_uptr video_decoder_; video_transformer_uptr video_transformer_; - //std::deque videoDecodedPacketChannel_; - std::deque video_frame_channel_; + std::deque video_frame_channel_; - // Filter 3 : Audio Decoding audio_decoder_ptr audio_decoder_; std::deque> audio_chunk_channel_; - // Filter 4 : Merge Video and Audio - std::queue ouput_channel_; + std::queue ouput_channel_; std::wstring filename_; + + long underrun_count_; }; frame_producer_ptr create_ffmpeg_producer(const std::vector& params) diff --git a/core/producer/ffmpeg/input.cpp b/core/producer/ffmpeg/input.cpp index 8a7fdf713..2b2dbbc9d 100644 --- a/core/producer/ffmpeg/input.cpp +++ b/core/producer/ffmpeg/input.cpp @@ -2,7 +2,7 @@ #include "input.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include "../../../common/utility/memory.h" #include "../../../common/utility/scope_exit.h" @@ -32,13 +32,12 @@ namespace caspar { namespace core { namespace ffmpeg{ struct input::implementation : boost::noncopyable { - implementation() - : video_frame_rate_(25.0), video_s_index_(-1), audio_s_index_(-1), video_codec_(nullptr), audio_codec_(nullptr) + implementation() : video_s_index_(-1), audio_s_index_(-1), video_codec_(nullptr), audio_codec_(nullptr) { loop_ = false; //file_buffer_size_ = 0; - video_packet_buffer_.set_capacity(25); - audio_packet_buffer_.set_capacity(25); + video_packet_buffer_.set_capacity(50); + audio_packet_buffer_.set_capacity(50); } ~implementation() @@ -78,16 +77,13 @@ struct input::implementation : boost::noncopyable CASPAR_LOG(warning) << "No audio stream found."; if(!video_codec_context_ && !audio_codex_context_) - BOOST_THROW_EXCEPTION(file_read_error() << msg_info("No video or audio codec found.")); - - video_frame_rate_ = static_cast(video_codec_context_->time_base.den) / static_cast(video_codec_context_->time_base.num); + BOOST_THROW_EXCEPTION(file_read_error() << msg_info("No video or audio codec found.")); } catch(...) { video_codec_context_.reset(); audio_codex_context_.reset(); format_context_.reset(); - video_frame_rate_ = 25.0; video_s_index_ = -1; audio_s_index_ = -1; throw; @@ -157,11 +153,13 @@ struct input::implementation : boost::noncopyable if(packet->stream_index == video_s_index_) { video_packet_buffer_.push(std::make_shared(packet->data, packet->data + packet->size)); + packet_wait_cond_.notify_all(); //file_buffer_size_ += packet->size; } else if(packet->stream_index == audio_s_index_) { - audio_packet_buffer_.push(std::make_shared(packet->data, packet->data + packet->size)); + audio_packet_buffer_.push(std::make_shared(packet->data, packet->data + packet->size)); + packet_wait_cond_.notify_all(); //file_buffer_size_ += packet->size; } } @@ -209,6 +207,13 @@ struct input::implementation : boost::noncopyable { return !is_running_ && video_packet_buffer_.empty() && audio_packet_buffer_.empty(); } + + void wait_for_packet() + { + boost::unique_lock lock(packet_wait_mutex_); + while(is_running_ && video_packet_buffer_.empty() && audio_packet_buffer_.empty()) + packet_wait_cond_.wait(lock); + } bool seek(unsigned long long seek_target) { @@ -228,15 +233,19 @@ struct input::implementation : boost::noncopyable return false; } - //int file_buffer_max_size_; + //int file_buffer_max_size_; //tbb::atomic file_buffer_size_; //boost::condition_variable file_buffer_size_cond_; //boost::mutex file_buffer_size_mutex_; - + + boost::condition_variable packet_wait_cond_; + boost::mutex packet_wait_mutex_; + + std::shared_ptr format_context_; // Destroy this last + tbb::queuing_mutex seek_mutex_; std::string filename_; - std::shared_ptr format_context_; // Destroy this last std::shared_ptr video_codec_context_; AVCodec* video_codec_; @@ -252,8 +261,6 @@ struct input::implementation : boost::noncopyable tbb::concurrent_bounded_queue> audio_packet_buffer_; boost::thread io_thread_; tbb::atomic is_running_; - - double video_frame_rate_; }; input::input() : impl_(new implementation()){} @@ -266,4 +273,5 @@ aligned_buffer input::get_video_packet(){return impl_->get_video_packet();} aligned_buffer input::get_audio_packet(){return impl_->get_audio_packet();} bool input::seek(unsigned long long frame){return impl_->seek(frame);} void input::start(){impl_->start();} +void input::wait_for_packet(){impl_->wait_for_packet();} }}} \ No newline at end of file diff --git a/core/producer/ffmpeg/input.h b/core/producer/ffmpeg/input.h index 17ffc6c1f..73ddac186 100644 --- a/core/producer/ffmpeg/input.h +++ b/core/producer/ffmpeg/input.h @@ -20,6 +20,7 @@ public: aligned_buffer get_video_packet(); aligned_buffer get_audio_packet(); + void wait_for_packet(); bool seek(unsigned long long frame); void start(); diff --git a/core/producer/ffmpeg/video/video_decoder.cpp b/core/producer/ffmpeg/video/video_decoder.cpp index 2a1f17995..1f1fdc4f8 100644 --- a/core/producer/ffmpeg/video/video_decoder.cpp +++ b/core/producer/ffmpeg/video/video_decoder.cpp @@ -24,8 +24,7 @@ struct video_decoder::implementation : boost::noncopyable std::shared_ptr execute(const aligned_buffer& video_packet) { - std::shared_ptr decoded_frame; - decoded_frame.reset(avcodec_alloc_frame(), av_free); + std::shared_ptr decoded_frame(avcodec_alloc_frame(), av_free); int frame_finished = 0; if((-avcodec_decode_video(codec_context_, decoded_frame.get(), &frame_finished, video_packet.data(), video_packet.size())) > 0) diff --git a/core/producer/ffmpeg/video/video_transformer.cpp b/core/producer/ffmpeg/video/video_transformer.cpp index 47ca67bf1..c20d16342 100644 --- a/core/producer/ffmpeg/video/video_transformer.cpp +++ b/core/producer/ffmpeg/video/video_transformer.cpp @@ -2,7 +2,7 @@ #include "video_transformer.h" -#include "../../../video/video_format.h" +#include "../../../format/video_format.h" #include "../../../../common/utility/memory.h" #include "../../../processor/frame.h" #include "../../../processor/frame.h" @@ -63,6 +63,9 @@ struct video_transformer::implementation : boost::noncopyable frame_ptr execute(const std::shared_ptr& decoded_frame) { + if(decoded_frame == nullptr) + return nullptr; + int width = codec_context_->width; int height = codec_context_->height; auto pix_fmt = codec_context_->pix_fmt; diff --git a/core/producer/flash/FlashAxContainer.cpp b/core/producer/flash/FlashAxContainer.cpp index b95369d5e..d11f32756 100644 --- a/core/producer/flash/FlashAxContainer.cpp +++ b/core/producer/flash/FlashAxContainer.cpp @@ -21,7 +21,7 @@ #include "..\..\stdafx.h" #include "FlashAxContainer.h" -#include "..\..\video\video_format.h" +#include "..\..\format\video_format.h" #include "flash_producer.h" #include "TimerHelper.h" diff --git a/core/producer/flash/FlashAxContainer.h b/core/producer/flash/FlashAxContainer.h index d480006de..996b7e0ba 100644 --- a/core/producer/flash/FlashAxContainer.h +++ b/core/producer/flash/FlashAxContainer.h @@ -36,7 +36,7 @@ #pragma warning(push) #include "..\..\processor\frame.h" -#include "..\..\video\video_format.h" +#include "..\..\format\video_format.h" #include #include diff --git a/core/producer/flash/cg_producer.cpp b/core/producer/flash/cg_producer.cpp index fb34d92d8..e50683d5f 100644 --- a/core/producer/flash/cg_producer.cpp +++ b/core/producer/flash/cg_producer.cpp @@ -8,7 +8,7 @@ #include "flash_producer.h" #include "../../producer/frame_producer_device.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include "../../processor/frame.h" #include "../../Server.h" diff --git a/core/producer/flash/cg_producer.h b/core/producer/flash/cg_producer.h index 997f5cd31..d63dbcbca 100644 --- a/core/producer/flash/cg_producer.h +++ b/core/producer/flash/cg_producer.h @@ -1,7 +1,7 @@ #pragma once #include "../frame_producer.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include "../../channel.h" namespace caspar { namespace core { namespace flash{ diff --git a/core/producer/flash/flash_producer.cpp b/core/producer/flash/flash_producer.cpp index b20646223..50b1adf10 100644 --- a/core/producer/flash/flash_producer.cpp +++ b/core/producer/flash/flash_producer.cpp @@ -29,7 +29,7 @@ #include "TimerHelper.h" #include "bitmap.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include "../../../common/utility/find_file.h" #include "../../server.h" #include "../../../common/concurrency/executor.h" diff --git a/core/producer/frame_producer_device.cpp b/core/producer/frame_producer_device.cpp index 744e6c1d2..11861aef3 100644 --- a/core/producer/frame_producer_device.cpp +++ b/core/producer/frame_producer_device.cpp @@ -4,7 +4,7 @@ #include "layer.h" -#include "../video/video_format.h" +#include "../format/video_format.h" #include "../processor/composite_frame.h" #include "../../common/utility/scope_exit.h" diff --git a/core/producer/frame_producer_device.h b/core/producer/frame_producer_device.h index 4c06d5f9f..812ecdd10 100644 --- a/core/producer/frame_producer_device.h +++ b/core/producer/frame_producer_device.h @@ -2,7 +2,7 @@ #include "../processor/frame_processor_device.h" #include "../consumer/frame_consumer.h" -#include "../video/video_format.h" +#include "../format/video_format.h" #include "layer.h" diff --git a/core/producer/image/image_producer.cpp b/core/producer/image/image_producer.cpp index ea16838b5..c527f1bb9 100644 --- a/core/producer/image/image_producer.cpp +++ b/core/producer/image/image_producer.cpp @@ -4,7 +4,7 @@ #include "image_loader.h" #include "../../processor/frame_processor_device.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include "../../server.h" #include "../../../common/utility/find_file.h" #include "../../../common/utility/memory.h" diff --git a/core/producer/image/image_scroll_producer.cpp b/core/producer/image/image_scroll_producer.cpp index dc41bdc45..4c33b0355 100644 --- a/core/producer/image/image_scroll_producer.cpp +++ b/core/producer/image/image_scroll_producer.cpp @@ -6,7 +6,7 @@ #include "../../processor/frame.h" #include "../../processor/composite_frame.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include "../../processor/frame_processor_device.h" #include "../../server.h" #include "../../../common/utility/find_file.h" diff --git a/core/producer/layer.cpp b/core/producer/layer.cpp index c053ea733..4ae74bbb9 100644 --- a/core/producer/layer.cpp +++ b/core/producer/layer.cpp @@ -4,7 +4,7 @@ #include "../producer/frame_producer.h" -#include "../video/video_format.h" +#include "../format/video_format.h" namespace caspar { namespace core { diff --git a/core/producer/transition/transition_producer.cpp b/core/producer/transition/transition_producer.cpp index 6a24c1384..b1e335d06 100644 --- a/core/producer/transition/transition_producer.cpp +++ b/core/producer/transition/transition_producer.cpp @@ -21,7 +21,7 @@ #include "transition_producer.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include "../../processor/frame.h" #include "../../processor/composite_frame.h" #include "../../processor/frame_processor_device.h" diff --git a/core/protocol/amcp/AMCPCommandsImpl.cpp b/core/protocol/amcp/AMCPCommandsImpl.cpp index f178266d6..89214df1b 100644 --- a/core/protocol/amcp/AMCPCommandsImpl.cpp +++ b/core/protocol/amcp/AMCPCommandsImpl.cpp @@ -23,7 +23,7 @@ #include "AMCPCommandsImpl.h" #include "AMCPProtocolStrategy.h" #include "../../producer/frame_producer.h" -#include "../../video/video_format.h" +#include "../../format/video_format.h" #include "../../producer/flash/flash_producer.h" #include "../../producer/transition/transition_producer.h" #include diff --git a/shell/caspar.config b/shell/caspar.config index f8a7e2353..9c3d9cb9b 100644 --- a/shell/caspar.config +++ b/shell/caspar.config @@ -24,9 +24,9 @@ - + \ No newline at end of file diff --git a/shell/shell.vcxproj b/shell/shell.vcxproj index 827af8b15..1c984a7c8 100644 --- a/shell/shell.vcxproj +++ b/shell/shell.vcxproj @@ -140,7 +140,7 @@ ProgramDatabase true NDEBUG;_VC80_UPGRADE=0x0710;%(PreprocessorDefinitions) - false + true true