1 #include "../../stdafx.h"
\r
3 #include "ffmpeg_producer.h"
\r
5 #if defined(_MSC_VER)
\r
6 #pragma warning (push)
\r
7 #pragma warning (disable : 4244)
\r
12 #define __STDC_CONSTANT_MACROS
\r
13 #define __STDC_LIMIT_MACROS
\r
14 #include <libavcodec/avcodec.h>
\r
15 #include <libavformat/avformat.h>
\r
16 #include <libavutil/avutil.h>
\r
17 #include <libswscale/swscale.h>
\r
20 #if defined(_MSC_VER)
\r
21 #pragma warning (pop)
\r
26 #include "audio/audio_decoder.h"
\r
27 #include "video/video_decoder.h"
\r
28 #include "video/video_transformer.h"
\r
30 #include "../../frame/frame_format.h"
\r
31 #include "../../../common/utility/find_file.h"
\r
32 #include "../../../common/utility/memory.h"
\r
33 #include "../../../common/utility/scope_exit.h"
\r
34 #include "../../server.h"
\r
36 #include <tbb/mutex.h>
\r
37 #include <tbb/parallel_invoke.h>
\r
38 #include <tbb/task_group.h>
\r
40 #include <boost/algorithm/string/case_conv.hpp>
\r
41 #include <boost/lexical_cast.hpp>
\r
42 #include <boost/thread.hpp>
\r
43 #include <boost/thread/once.hpp>
\r
45 using namespace boost::assign;
\r
47 namespace caspar { namespace core { namespace ffmpeg{
\r
49 struct ffmpeg_producer : public frame_producer
\r
52 ffmpeg_producer(const std::wstring& filename, const std::vector<std::wstring>& params, const frame_format_desc& format_desc)
\r
53 : filename_(filename), format_desc_(format_desc)
\r
55 if(!boost::filesystem::exists(filename))
\r
56 BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(common::narrow(filename)));
\r
58 static boost::once_flag flag = BOOST_ONCE_INIT;
\r
59 boost::call_once(av_register_all, flag);
\r
61 input_.reset(new input(format_desc_));
\r
62 input_->set_loop(std::find(params.begin(), params.end(), L"LOOP") != params.end());
\r
63 input_->load(common::narrow(filename_));
\r
64 video_decoder_.reset(new video_decoder());
\r
65 video_transformer_.reset(new video_transformer());
\r
66 audio_decoder_.reset(new audio_decoder());
\r
67 has_audio_ = input_->get_audio_codec_context() != nullptr;
\r
69 auto seek = std::find(params.begin(), params.end(), L"SEEK");
\r
70 if(seek != params.end() && ++seek != params.end())
\r
72 if(!input_->seek(boost::lexical_cast<unsigned long long>(*seek)))
\r
73 CASPAR_LOG(warning) << "Failed to seek file: " << filename_ << "to frame" << *seek;
\r
79 void initialize(const frame_factory_ptr& factory)
\r
81 video_transformer_->initialize(factory);
\r
84 gpu_frame_ptr render_frame()
\r
86 while(ouput_channel_.empty() && !input_->is_eof())
\r
88 tbb::parallel_invoke(
\r
90 { // Video Decoding and Scaling
\r
91 auto video_packet = input_->get_video_packet();
\r
94 video_packet = video_decoder_->execute(video_packet);
\r
95 auto frame = video_transformer_->execute(video_packet)->frame;
\r
96 video_frame_channel_.push_back(std::move(frame));
\r
100 { // Audio Decoding
\r
101 auto audio_packet = input_->get_audio_packet();
\r
104 audio_decoder_->execute(audio_packet);
\r
105 for(size_t n = 0; n < audio_packet->audio_chunks.size(); ++n)
\r
106 audio_chunk_channel_.push_back(std::move(audio_packet->audio_chunks[n]));
\r
110 while(!video_frame_channel_.empty() && (!audio_chunk_channel_.empty() || !has_audio_))
\r
114 video_frame_channel_.front()->audio_data() = std::move(audio_chunk_channel_.front());
\r
115 audio_chunk_channel_.pop_front();
\r
118 gpu_frame_ptr frame = video_frame_channel_.front();
\r
119 video_frame_channel_.pop_front();
\r
120 ouput_channel_.push(std::move(frame));
\r
124 gpu_frame_ptr frame;
\r
125 if(!ouput_channel_.empty())
\r
127 frame = ouput_channel_.front();
\r
128 ouput_channel_.pop();
\r
133 const frame_format_desc& get_frame_format_desc() const { return format_desc_; }
\r
137 // Filter 1 : Input
\r
138 input_uptr input_;
\r
140 // Filter 2 : Video Decoding and Scaling
\r
141 video_decoder_uptr video_decoder_;
\r
142 video_transformer_uptr video_transformer_;
\r
143 //std::deque<video_packet_ptr> videoDecodedPacketChannel_;
\r
144 std::deque<gpu_frame_ptr> video_frame_channel_;
\r
146 // Filter 3 : Audio Decoding
\r
147 audio_decoder_uptr audio_decoder_;
\r
148 std::deque<std::vector<short>> audio_chunk_channel_;
\r
150 // Filter 4 : Merge Video and Audio
\r
151 std::queue<gpu_frame_ptr> ouput_channel_;
\r
153 std::wstring filename_;
\r
154 frame_format_desc format_desc_;
\r
157 frame_producer_ptr create_ffmpeg_producer(const std::vector<std::wstring>& params, const frame_format_desc& format_desc)
\r
159 std::wstring filename = params[0];
\r
160 std::wstring result_filename = common::find_file(server::media_folder() + filename, list_of(L"mpg")(L"avi")(L"mov")(L"dv")(L"wav")(L"mp3")(L"mp4")(L"f4v")(L"flv"));
\r
161 if(result_filename.empty())
\r
164 return std::make_shared<ffmpeg_producer>(result_filename, params, format_desc);
\r