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 "../../video/video_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)
\r
53 : filename_(filename)
\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());
\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(input_->get_video_codec_context().get()));
\r
65 video_transformer_.reset(new video_transformer(input_->get_video_codec_context().get()));
\r
66 audio_decoder_.reset(new audio_decoder(input_->get_audio_codec_context().get()));
\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_processor_device_ptr& frame_processor)
\r
81 video_transformer_->initialize(frame_processor);
\r
84 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
92 if(!video_packet.empty())
\r
94 auto decoded_frame = video_decoder_->execute(video_packet);
\r
95 auto transformed_frame = video_transformer_->execute(decoded_frame);
\r
96 video_frame_channel_.push_back(transformed_frame);
\r
100 { // Audio Decoding
\r
101 auto audio_packet = input_->get_audio_packet();
\r
102 if(!audio_packet.empty())
\r
104 auto chunks = audio_decoder_->execute(audio_packet);
\r
105 audio_chunk_channel_.insert(audio_chunk_channel_.end(), chunks.begin(), chunks.end());
\r
109 while(!video_frame_channel_.empty() && (!audio_chunk_channel_.empty() || !has_audio_))
\r
113 video_frame_channel_.front()->audio_data() = std::move(audio_chunk_channel_.front());
\r
114 audio_chunk_channel_.pop_front();
\r
117 frame_ptr frame = video_frame_channel_.front();
\r
118 video_frame_channel_.pop_front();
\r
119 ouput_channel_.push(std::move(frame));
\r
124 if(!ouput_channel_.empty())
\r
126 frame = ouput_channel_.front();
\r
127 ouput_channel_.pop();
\r
134 // Filter 1 : Input
\r
135 input_uptr input_;
\r
137 // Filter 2 : Video Decoding and Scaling
\r
138 video_decoder_uptr video_decoder_;
\r
139 video_transformer_uptr video_transformer_;
\r
140 //std::deque<video_packet_ptr> videoDecodedPacketChannel_;
\r
141 std::deque<frame_ptr> video_frame_channel_;
\r
143 // Filter 3 : Audio Decoding
\r
144 audio_decoder_ptr audio_decoder_;
\r
145 std::deque<std::vector<short>> audio_chunk_channel_;
\r
147 // Filter 4 : Merge Video and Audio
\r
148 std::queue<frame_ptr> ouput_channel_;
\r
150 std::wstring filename_;
\r
153 frame_producer_ptr create_ffmpeg_producer(const std::vector<std::wstring>& params)
\r
155 std::wstring filename = params[0];
\r
156 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
157 if(result_filename.empty())
\r
160 return std::make_shared<ffmpeg_producer>(result_filename, params);
\r