diag_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
diag_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f));\r
diag_->set_color("input-buffer", diagnostics::color(1.0f, 1.0f, 0.0f)); \r
- executor_.set_capacity(1); \r
+ executor_.set_capacity(2); \r
executor_.begin_invoke([]\r
{\r
SetThreadPriority(GetCurrentThread(), ABOVE_NORMAL_PRIORITY_CLASS);\r
\r
#include <tbb/atomic.h>\r
#include <tbb/concurrent_queue.h>\r
-#include <tbb/concurrent_unordered_map.h>\r
#include <tbb/parallel_invoke.h>\r
#include <tbb/parallel_for.h>\r
-#include <tbb/parallel_for_each.h>\r
\r
#include <boost/assign.hpp>\r
#include <boost/filesystem.hpp>\r
#include <boost/foreach.hpp>\r
#include <boost/range/algorithm.hpp>\r
\r
-#include "../common/utility/string.h"\r
-#include "../common/memory/safe_ptr.h"\r
+#include <common/utility/string.h>\r
+#include <common/utility/assert.h>\r
+#include <common/memory/safe_ptr.h>\r
//#include "../common/concurrency/executor.h" // Can't include this due to MSVC lambda bug\r
\r
-#include "../common/log/Log.h"\r
-#include "../common/exception/exceptions.h"\r
-#include "../common/exception/win32_exception.h"\r
+#include <common/log/log.h>\r
+#include <common/exception/exceptions.h>\r
+#include <common/exception/win32_exception.h>\r
\r
-#include <assert.h>\r
+#pragma warning(push, 1)\r
+\r
+extern "C" \r
+{\r
+ #define __STDC_CONSTANT_MACROS\r
+ #define __STDC_LIMIT_MACROS\r
+ #include <libavformat/avformat.h>\r
+ #include <libavcodec/avcodec.h>\r
+ #include <libswscale/swscale.h>\r
+}\r
+\r
+#pragma warning(pop)\r
\r
#endif\r
\r
struct audio_decoder::implementation : boost::noncopyable\r
{\r
- typedef std::vector<short, tbb::cache_aligned_allocator<short>> buffer;\r
+ typedef std::vector<short, tbb::cache_aligned_allocator<short>> aligned_buffer;\r
\r
- AVCodecContext* codec_context_;\r
+ AVCodecContext& codec_context_;\r
\r
const core::video_format_desc format_desc_;\r
\r
- buffer current_chunk_;\r
+ aligned_buffer current_chunk_;\r
\r
public:\r
- explicit implementation(AVCodecContext* codec_context, const core::video_format_desc& format_desc) \r
+ explicit implementation(AVCodecContext& codec_context, const core::video_format_desc& format_desc) \r
: codec_context_(codec_context)\r
, format_desc_(format_desc) \r
{\r
- if(!codec_context)\r
- { \r
- BOOST_THROW_EXCEPTION(\r
- null_argument() << \r
- arg_name_info("codec_context")); \r
- }\r
-\r
- if(codec_context_->sample_rate != static_cast<int>(format_desc_.audio_sample_rate) || \r
- codec_context_->channels != static_cast<int>(format_desc_.audio_channels))\r
+ if(codec_context_.sample_rate != static_cast<int>(format_desc_.audio_sample_rate) || \r
+ codec_context_.channels != static_cast<int>(format_desc_.audio_channels))\r
{ \r
BOOST_THROW_EXCEPTION(\r
file_read_error() <<\r
msg_info("Invalid sample-rate or number of channels.") <<\r
- arg_value_info(boost::lexical_cast<std::string>(codec_context_->sample_rate)) << \r
+ arg_value_info(boost::lexical_cast<std::string>(codec_context_.sample_rate)) << \r
arg_name_info("codec_context"));\r
}\r
}\r
switch(audio_packet.type)\r
{\r
case flush_packet:\r
- avcodec_flush_buffers(codec_context_);\r
+ avcodec_flush_buffers(&codec_context_);\r
break;\r
case data_packet:\r
auto s = current_chunk_.size();\r
current_chunk_.resize(s + 4*format_desc_.audio_sample_rate*2+FF_INPUT_BUFFER_PADDING_SIZE/2);\r
\r
int written_bytes = (current_chunk_.size() - s)*2 - FF_INPUT_BUFFER_PADDING_SIZE;\r
- const int errn = avcodec_decode_audio2(codec_context_, ¤t_chunk_[s], &written_bytes, audio_packet.data->data(), audio_packet.data->size());\r
+ const int errn = avcodec_decode_audio2(&codec_context_, ¤t_chunk_[s], &written_bytes, audio_packet.data->data(), audio_packet.data->size());\r
if(errn < 0)\r
{ \r
BOOST_THROW_EXCEPTION(\r
}\r
};\r
\r
-audio_decoder::audio_decoder(AVCodecContext* codec_context, const core::video_format_desc& format_desc) : impl_(new implementation(codec_context, format_desc)){}\r
+audio_decoder::audio_decoder(AVCodecContext& codec_context, const core::video_format_desc& format_desc) : impl_(new implementation(codec_context, format_desc)){}\r
std::vector<std::vector<short>> audio_decoder::execute(const packet& audio_packet){return impl_->execute(audio_packet);}\r
}
\ No newline at end of file
class audio_decoder : boost::noncopyable\r
{\r
public:\r
- explicit audio_decoder(AVCodecContext* codec_context, const core::video_format_desc& format_desc);\r
+ explicit audio_decoder(AVCodecContext& codec_context, const core::video_format_desc& format_desc);\r
std::vector<std::vector<short>> execute(const packet& audio_packet);\r
private:\r
struct implementation;\r
#include <tbb/parallel_invoke.h>\r
\r
#include <boost/timer.hpp>\r
+#include <boost/range/algorithm.hpp>\r
+#include <boost/range/algorithm_ext.hpp>\r
\r
#include <deque>\r
\r
\r
struct ffmpeg_producer : public core::frame_producer\r
{\r
+ static const size_t DECODED_PACKET_BUFFER_SIZE = 4;\r
+ static const size_t MAX_PACKET_OFFSET = 64; // 64 packets should be enough. Otherwise there probably was an error and we want to avoid infinite looping.\r
+\r
const std::wstring filename_;\r
const bool loop_;\r
\r
try\r
{ \r
video_decoder_.reset(input_.get_video_codec_context() ? \r
- new video_decoder(input_.get_video_codec_context().get(), frame_factory) : nullptr);\r
+ new video_decoder(*input_.get_video_codec_context(), frame_factory) : nullptr);\r
}\r
catch(...)\r
{\r
try\r
{ \r
audio_decoder_.reset(input_.get_audio_codec_context() ? \r
- new audio_decoder(input_.get_audio_codec_context().get(), frame_factory->get_video_format_desc()) : nullptr);\r
+ new audio_decoder(*input_.get_audio_codec_context(), frame_factory->get_video_format_desc()) : nullptr);\r
}\r
catch(...)\r
{\r
frame_timer_.restart();\r
\r
std::shared_ptr<core::basic_frame> frame; \r
- for(size_t n = 0; !frame && input_.has_packet() && n < 64; ++n) // 64 packets should be enough. Otherwise there probably was an error and we want to avoid infinite looping.\r
- { \r
- tbb::parallel_invoke\r
- (\r
- [&]\r
- {\r
- if(video_frame_buffer_.size() < 3)\r
- try_decode_video_packet(input_.get_video_packet());\r
- }, \r
- [&]\r
- {\r
- if(audio_chunk_buffer_.size() < 3)\r
- try_decode_audio_packet(input_.get_audio_packet());\r
- }\r
- ); \r
-\r
- frame = try_merge_audio_and_video(); \r
- }\r
+ for(size_t n = 0; !frame && n < MAX_PACKET_OFFSET; ++n) \r
+ frame = try_decode_frame();\r
\r
graph_->update_value("frame-time", static_cast<float>(frame_timer_.elapsed()*frame_factory_->get_video_format_desc().fps*0.5));\r
\r
graph_->add_tag("underflow");\r
return core::basic_frame::late(); \r
}\r
-\r
+ \r
virtual std::wstring print() const\r
{\r
return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"]";\r
}\r
+ \r
+ std::shared_ptr<core::basic_frame> try_decode_frame()\r
+ {\r
+ if(!input_.has_packet())\r
+ return nullptr;\r
+\r
+ tbb::parallel_invoke\r
+ (\r
+ [&]\r
+ {\r
+ if(video_frame_buffer_.size() < DECODED_PACKET_BUFFER_SIZE)\r
+ try_decode_video_packet(input_.get_video_packet());\r
+ }, \r
+ [&]\r
+ {\r
+ if(audio_chunk_buffer_.size() < DECODED_PACKET_BUFFER_SIZE)\r
+ try_decode_audio_packet(input_.get_audio_packet());\r
+ }\r
+ ); \r
+\r
+ return try_merge_audio_and_video(); \r
+ }\r
\r
void try_decode_video_packet(const packet& video_packet)\r
{\r
- if(!video_decoder_) // Video Decoding.\r
+ if(!video_decoder_)\r
return;\r
\r
try\r
{\r
- auto frames = video_decoder_->execute(this, video_packet);\r
- video_frame_buffer_.insert(video_frame_buffer_.end(), frames.begin(), frames.end());\r
+ boost::range::push_back(video_frame_buffer_, video_decoder_->execute(this, video_packet));\r
}\r
catch(...)\r
{\r
\r
void try_decode_audio_packet(const packet& audio_packet)\r
{\r
- if(!audio_decoder_) // Audio Decoding.\r
+ if(!audio_decoder_)\r
return;\r
\r
try\r
{\r
- auto chunks = audio_decoder_->execute(audio_packet);\r
- audio_chunk_buffer_.insert(audio_chunk_buffer_.end(), chunks.begin(), chunks.end());\r
+ boost::range::push_back(audio_chunk_buffer_, audio_decoder_->execute(audio_packet));\r
}\r
catch(...)\r
{\r
* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
*\r
*/\r
+#if defined(_MSC_VER)\r
+#pragma warning (disable : 4244)\r
+#endif\r
+\r
#include "..\stdafx.h"\r
\r
#include "input.h"\r
#include <boost/range/iterator_range.hpp>\r
#include <boost/range/algorithm.hpp>\r
\r
-#if defined(_MSC_VER)\r
-#pragma warning (disable : 4244)\r
-#endif\r
\r
extern "C" \r
{\r
\r
struct input::implementation : boost::noncopyable\r
{ \r
- static const size_t PACKET_BUFFER_COUNT = 25;\r
+ static const size_t PACKET_BUFFER_COUNT = 50;\r
\r
safe_ptr<diagnostics::graph> graph_;\r
\r
\r
void read_file()\r
{ \r
+ if(audio_packet_buffer_.size() > 4 && video_packet_buffer_.size() > 4)\r
+ boost::this_thread::yield(); // There is enough packets, no hurry.\r
+\r
try\r
{\r
AVPacket tmp_packet;\r
{ \r
std::shared_ptr<SwsContext> sws_context_;\r
const std::shared_ptr<core::frame_factory> frame_factory_;\r
- AVCodecContext* codec_context_;\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
+ explicit implementation(AVCodecContext& codec_context, const safe_ptr<core::frame_factory>& frame_factory) \r
: frame_factory_(frame_factory)\r
, codec_context_(codec_context)\r
- , width_(codec_context_->width)\r
- , height_(codec_context_->height)\r
- , pix_fmt_(codec_context_->pix_fmt)\r
+ , width_(codec_context_.width)\r
+ , height_(codec_context_.height)\r
+ , pix_fmt_(codec_context_.pix_fmt)\r
, desc_(get_pixel_format_desc(pix_fmt_, width_, height_))\r
{\r
if(desc_.pix_fmt == core::pixel_format::invalid)\r
switch(video_packet.type)\r
{\r
case flush_packet:\r
- avcodec_flush_buffers(codec_context_);\r
+ avcodec_flush_buffers(&codec_context_);\r
break;\r
case data_packet: \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->data(), video_packet.data->size());\r
+ const int errn = avcodec_decode_video(&codec_context_, decoded_frame.get(), &frame_finished, video_packet.data->data(), video_packet.data->size());\r
\r
if(errn < 0)\r
{\r
} \r
\r
// DVVIDEO is in lower field. Make it upper field if needed.\r
- if(codec_context_->codec_id == CODEC_ID_DVVIDEO && frame_factory_->get_video_format_desc().mode == core::video_mode::upper)\r
+ if(codec_context_.codec_id == CODEC_ID_DVVIDEO && frame_factory_->get_video_format_desc().mode == core::video_mode::upper)\r
write->get_image_transform().set_fill_translation(0.0f, 1.0/static_cast<double>(height_));\r
\r
return write;\r
}\r
};\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
+video_decoder::video_decoder(AVCodecContext& codec_context, const safe_ptr<core::frame_factory>& frame_factory) : impl_(new implementation(codec_context, frame_factory)){}\r
std::vector<safe_ptr<core::write_frame>> video_decoder::execute(void* tag, const packet& video_packet){return impl_->execute(tag, video_packet);}\r
\r
}
\ No newline at end of file
class video_decoder : boost::noncopyable\r
{\r
public:\r
- explicit video_decoder(AVCodecContext* codec_context, const safe_ptr<core::frame_factory>& frame_factory);\r
+ explicit video_decoder(AVCodecContext& codec_context, const safe_ptr<core::frame_factory>& frame_factory);\r
std::vector<safe_ptr<core::write_frame>> execute(void* tag, const packet& video_packet); \r
private:\r
struct implementation;\r