X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=modules%2Fffmpeg%2Fproducer%2Futil%2Futil.cpp;h=7677bd807e83af4c7978db066cd95f1c866e1ad5;hb=3cccad0a2d401c4452274939f9729a3c4aa923cc;hp=dd170c15514e7d5903aff2ac5ea9885cbcda7815;hpb=816ec4de7305e1250cc5c698c9d2cccb08d691dc;p=casparcg diff --git a/modules/ffmpeg/producer/util/util.cpp b/modules/ffmpeg/producer/util/util.cpp index dd170c155..7677bd807 100644 --- a/modules/ffmpeg/producer/util/util.cpp +++ b/modules/ffmpeg/producer/util/util.cpp @@ -31,20 +31,22 @@ #include #include -#include -#include +#include +#include +#include #include -#include -#include -#include -#include +#include +#include #include +#include #include #include +#include + #if defined(_MSC_VER) #pragma warning (push) #pragma warning (disable : 4244) @@ -85,7 +87,7 @@ std::shared_ptr empty_video() return video; } -core::field_mode::type get_mode(const AVFrame& frame) +core::field_mode get_mode(const AVFrame& frame) { if(!frame.interlaced_frame) return core::field_mode::progressive; @@ -93,7 +95,7 @@ core::field_mode::type get_mode(const AVFrame& frame) return frame.top_field_first ? core::field_mode::upper : core::field_mode::lower; } -core::pixel_format::type get_pixel_format(PixelFormat pix_fmt) +core::pixel_format get_pixel_format(PixelFormat pix_fmt) { switch(pix_fmt) { @@ -113,16 +115,15 @@ core::pixel_format::type get_pixel_format(PixelFormat pix_fmt) } } -core::pixel_format_desc get_pixel_format_desc(PixelFormat pix_fmt, size_t width, size_t height) +core::pixel_format_desc pixel_format_desc(PixelFormat pix_fmt, int width, int height) { // Get linesizes AVPicture dummy_pict; avpicture_fill(&dummy_pict, nullptr, pix_fmt == CASPAR_PIX_FMT_LUMA ? PIX_FMT_GRAY8 : pix_fmt, width, height); - core::pixel_format_desc desc; - desc.pix_fmt = get_pixel_format(pix_fmt); + core::pixel_format_desc desc = get_pixel_format(pix_fmt); - switch(desc.pix_fmt) + switch(desc.format.value()) { case core::pixel_format::gray: case core::pixel_format::luma: @@ -142,26 +143,26 @@ core::pixel_format_desc get_pixel_format_desc(PixelFormat pix_fmt, size_t width, case core::pixel_format::ycbcra: { // Find chroma height - size_t size2 = dummy_pict.data[2] - dummy_pict.data[1]; - size_t h2 = size2/dummy_pict.linesize[1]; + int size2 = static_cast(dummy_pict.data[2] - dummy_pict.data[1]); + int h2 = size2/dummy_pict.linesize[1]; desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[0], height, 1)); desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[1], h2, 1)); desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[2], h2, 1)); - if(desc.pix_fmt == core::pixel_format::ycbcra) + if(desc.format == core::pixel_format::ycbcra) desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[3], height, 1)); return desc; } default: - desc.pix_fmt = core::pixel_format::invalid; + desc.format = core::pixel_format::invalid; return desc; } } int make_alpha_format(int format) { - switch(get_pixel_format(static_cast(format))) + switch(get_pixel_format(static_cast(format)).value()) { case core::pixel_format::ycbcr: case core::pixel_format::ycbcra: @@ -171,23 +172,21 @@ int make_alpha_format(int format) } } -safe_ptr make_write_frame(const void* tag, const safe_ptr& decoded_frame, const safe_ptr& frame_factory, int hints) +core::mutable_frame make_frame(const void* tag, const spl::shared_ptr& decoded_frame, double fps, const spl::shared_ptr& frame_factory, int flags) { - static tbb::concurrent_unordered_map>> sws_contexts_; + static tbb::concurrent_unordered_map>> sws_contexts_; if(decoded_frame->width < 1 || decoded_frame->height < 1) - return make_safe(tag); + return frame_factory->create_frame(tag, core::pixel_format_desc(core::pixel_format::invalid)); const auto width = decoded_frame->width; const auto height = decoded_frame->height; - auto desc = get_pixel_format_desc(static_cast(decoded_frame->format), width, height); + auto desc = pixel_format_desc(static_cast(decoded_frame->format), width, height); - if(hints & core::frame_producer::ALPHA_HINT) - desc = get_pixel_format_desc(static_cast(make_alpha_format(decoded_frame->format)), width, height); - - std::shared_ptr write; - - if(desc.pix_fmt == core::pixel_format::invalid) + if(flags & core::frame_producer::flags::alpha_only) + desc = pixel_format_desc(static_cast(make_alpha_format(decoded_frame->format)), width, height); + + if(desc.format == core::pixel_format::invalid) { auto pix_fmt = static_cast(decoded_frame->format); auto target_pix_fmt = PIX_FMT_BGRA; @@ -205,16 +204,15 @@ safe_ptr make_write_frame(const void* tag, const safe_ptrcreate_frame(tag, target_desc); - write->set_type(get_mode(*decoded_frame)); + auto write = frame_factory->create_frame(tag, target_desc, fps, get_mode(*decoded_frame)); std::shared_ptr sws_context; //CASPAR_LOG(warning) << "Hardware accelerated color transform not supported."; - size_t key = ((width << 22) & 0xFFC00000) | ((height << 6) & 0x003FC000) | ((pix_fmt << 7) & 0x00007F00) | ((target_pix_fmt << 0) & 0x0000007F); + int key = ((width << 22) & 0xFFC00000) | ((height << 6) & 0x003FC000) | ((pix_fmt << 7) & 0x00007F00) | ((target_pix_fmt << 0) & 0x0000007F); auto& pool = sws_contexts_[key]; @@ -230,74 +228,122 @@ safe_ptr make_write_frame(const void* tag, const safe_ptr av_frame(avcodec_alloc_frame(), av_free); + spl::shared_ptr av_frame(avcodec_alloc_frame(), av_free); avcodec_get_frame_defaults(av_frame.get()); if(target_pix_fmt == PIX_FMT_BGRA) { - auto size = avpicture_fill(reinterpret_cast(av_frame.get()), write->image_data().begin(), PIX_FMT_BGRA, width, height); - CASPAR_VERIFY(size == write->image_data().size()); + auto size = avpicture_fill(reinterpret_cast(av_frame.get()), write.image_data(0).begin(), PIX_FMT_BGRA, width, height); + CASPAR_VERIFY(size == write.image_data(0).size()); } else { av_frame->width = width; av_frame->height = height; - for(size_t n = 0; n < target_desc.planes.size(); ++n) + for(int n = 0; n < target_desc.planes.size(); ++n) { - av_frame->data[n] = write->image_data(n).begin(); + av_frame->data[n] = write.image_data(n).begin(); av_frame->linesize[n] = target_desc.planes[n].linesize; } } sws_scale(sws_context.get(), decoded_frame->data, decoded_frame->linesize, 0, height, av_frame->data, av_frame->linesize); - pool.push(sws_context); + pool.push(sws_context); - write->commit(); + return std::move(write); } else { - write = frame_factory->create_frame(tag, desc); - write->set_type(get_mode(*decoded_frame)); - + auto write = frame_factory->create_frame(tag, desc, fps, get_mode(*decoded_frame)); + for(int n = 0; n < static_cast(desc.planes.size()); ++n) { auto plane = desc.planes[n]; - auto result = write->image_data(n).begin(); + auto result = write.image_data(n).begin(); auto decoded = decoded_frame->data[n]; auto decoded_linesize = decoded_frame->linesize[n]; CASPAR_ASSERT(decoded); - CASPAR_ASSERT(write->image_data(n).begin()); + CASPAR_ASSERT(write.image_data(n).begin()); - if(decoded_linesize != static_cast(plane.width)) - { - // Copy line by line since ffmpeg sometimes pads each line. - tbb::parallel_for(0, desc.planes[n].height, [&](size_t y) - { - fast_memcpy(result + y*plane.linesize, decoded + y*decoded_linesize, plane.linesize); - }); - } - else + // Copy line by line since ffmpeg sometimes pads each line. + tbb::affinity_partitioner ap; + tbb::parallel_for(tbb::blocked_range(0, desc.planes[n].height), [&](const tbb::blocked_range& r) { - fast_memcpy(result, decoded, plane.size); - } - - write->commit(n); + for(int y = r.begin(); y != r.end(); ++y) + A_memcpy(result + y*plane.linesize, decoded + y*decoded_linesize, plane.linesize); + }, ap); } + + return std::move(write); } +} - if(decoded_frame->height == 480) // NTSC DV - { - write->get_frame_transform().fill_translation[1] += 2.0/static_cast(frame_factory->get_video_format_desc().height); - write->get_frame_transform().fill_scale[1] = 1.0 - 6.0*1.0/static_cast(frame_factory->get_video_format_desc().height); - } +spl::shared_ptr make_av_frame(core::mutable_frame& frame) +{ + std::array data = {}; + for(int n = 0; n < frame.pixel_format_desc().planes.size(); ++n) + data[n] = frame.image_data(n).begin(); + + return make_av_frame(data, frame.pixel_format_desc()); +} + +spl::shared_ptr make_av_frame(std::array data, const core::pixel_format_desc& pix_desc) +{ + spl::shared_ptr av_frame(avcodec_alloc_frame(), av_free); + avcodec_get_frame_defaults(av_frame.get()); - // Fix field-order if needed - if(write->get_type() == core::field_mode::lower && frame_factory->get_video_format_desc().field_mode == core::field_mode::upper) - write->get_frame_transform().fill_translation[1] += 1.0/static_cast(frame_factory->get_video_format_desc().height); - else if(write->get_type() == core::field_mode::upper && frame_factory->get_video_format_desc().field_mode == core::field_mode::lower) - write->get_frame_transform().fill_translation[1] -= 1.0/static_cast(frame_factory->get_video_format_desc().height); + auto planes = pix_desc.planes; + auto format = pix_desc.format.value(); - return make_safe_ptr(write); + av_frame->width = planes[0].width; + av_frame->height = planes[0].height; + for(int n = 0; n < planes.size(); ++n) + { + av_frame->data[n] = data[n]; + av_frame->linesize[n] = planes[n].linesize; + } + switch(format) + { + case core::pixel_format::rgba: + av_frame->format = PIX_FMT_RGBA; + break; + case core::pixel_format::argb: + av_frame->format = PIX_FMT_ARGB; + break; + case core::pixel_format::bgra: + av_frame->format = PIX_FMT_BGRA; + break; + case core::pixel_format::abgr: + av_frame->format = PIX_FMT_ABGR; + break; + case core::pixel_format::gray: + av_frame->format = PIX_FMT_GRAY8; + break; + case core::pixel_format::ycbcr: + { + int y_w = planes[0].width; + int y_h = planes[0].height; + int c_w = planes[1].width; + int c_h = planes[1].height; + + if(c_h == y_h && c_w == y_w) + av_frame->format = PIX_FMT_YUV444P; + else if(c_h == y_h && c_w*2 == y_w) + av_frame->format = PIX_FMT_YUV422P; + else if(c_h == y_h && c_w*4 == y_w) + av_frame->format = PIX_FMT_YUV411P; + else if(c_h*2 == y_h && c_w*2 == y_w) + av_frame->format = PIX_FMT_YUV420P; + else if(c_h*2 == y_h && c_w*4 == y_w) + av_frame->format = PIX_FMT_YUV410P; + + break; + } + case core::pixel_format::ycbcra: + av_frame->format = PIX_FMT_YUVA420P; + break; + } + return av_frame; } bool is_sane_fps(AVRational time_base) @@ -334,7 +380,7 @@ double read_fps(AVFormatContext& context, double fail_value) AVRational time_base = video_context->time_base; - if(boost::filesystem2::path(context.filename).extension() == ".flv") + if(boost::filesystem::path(context.filename).extension().string() == ".flv") { try { @@ -372,7 +418,7 @@ double read_fps(AVFormatContext& context, double fail_value) double closest_fps = 0.0; for(int n = 0; n < core::video_format::count; ++n) { - auto format = core::video_format_desc::get(static_cast(n)); + auto format = core::video_format_desc(core::video_format(n)); double diff1 = std::abs(format.fps - fps); double diff2 = std::abs(closest_fps - fps); @@ -396,7 +442,7 @@ void fix_meta_data(AVFormatContext& context) auto video_stream = context.streams[video_index]; auto video_context = context.streams[video_index]->codec; - if(boost::filesystem2::path(context.filename).extension() == ".flv") + if(boost::filesystem::path(context.filename).extension().string() == ".flv") { try { @@ -419,9 +465,9 @@ void fix_meta_data(AVFormatContext& context) } } -safe_ptr create_packet() +spl::shared_ptr create_packet() { - safe_ptr packet(new AVPacket, [](AVPacket* p) + spl::shared_ptr packet(new AVPacket, [](AVPacket* p) { av_free_packet(p); delete p; @@ -431,7 +477,7 @@ safe_ptr create_packet() return packet; } -safe_ptr open_codec(AVFormatContext& context, enum AVMediaType type, int& index) +spl::shared_ptr open_codec(AVFormatContext& context, enum AVMediaType type, int& index) { AVCodec* decoder; index = THROW_ON_ERROR2(av_find_best_stream(&context, type, -1, -1, &decoder, 0), ""); @@ -439,20 +485,20 @@ safe_ptr open_codec(AVFormatContext& context, enum AVMediaType t // decoder = decoder->next; THROW_ON_ERROR2(tbb_avcodec_open(context.streams[index]->codec, decoder), ""); - return safe_ptr(context.streams[index]->codec, tbb_avcodec_close); + return spl::shared_ptr(context.streams[index]->codec, tbb_avcodec_close); } -safe_ptr open_input(const std::wstring& filename) +spl::shared_ptr open_input(const std::wstring& filename) { AVFormatContext* weak_context = nullptr; THROW_ON_ERROR2(avformat_open_input(&weak_context, u8(filename).c_str(), nullptr, nullptr), filename); - safe_ptr context(weak_context, av_close_input_file); + spl::shared_ptr context(weak_context, av_close_input_file); THROW_ON_ERROR2(avformat_find_stream_info(weak_context, nullptr), filename); fix_meta_data(*context); return context; } -std::wstring print_mode(size_t width, size_t height, double fps, bool interlaced) +std::wstring print_mode(int width, int height, double fps, bool interlaced) { std::wostringstream fps_ss; fps_ss << std::fixed << std::setprecision(2) << (!interlaced ? fps : 2.0 * fps); @@ -462,6 +508,9 @@ std::wstring print_mode(size_t width, size_t height, double fps, bool interlaced bool is_valid_file(const std::wstring filename) { + if(boost::filesystem::path(filename).extension() == ".m2t") + return true; + std::ifstream file(filename); std::vector buf; @@ -474,7 +523,7 @@ bool is_valid_file(const std::wstring filename) AVProbeData pb; pb.filename = u8(filename).c_str(); pb.buf = buf.data(); - pb.buf_size = buf.size(); + pb.buf_size = static_cast(buf.size()); int score = 0; return av_probe_input_format2(&pb, true, &score) != nullptr; @@ -482,12 +531,12 @@ bool is_valid_file(const std::wstring filename) std::wstring probe_stem(const std::wstring stem) { - auto stem2 = boost::filesystem2::wpath(stem); + auto stem2 = boost::filesystem::path(stem); auto dir = stem2.parent_path(); - for(auto it = boost::filesystem2::wdirectory_iterator(dir); it != boost::filesystem2::wdirectory_iterator(); ++it) + for(auto it = boost::filesystem::directory_iterator(dir); it != boost::filesystem::directory_iterator(); ++it) { - if(boost::iequals(it->path().stem(), stem2.filename()) && is_valid_file(it->path().file_string())) - return it->path().file_string(); + if(boost::iequals(it->path().stem().wstring(), stem2.filename().wstring()) && is_valid_file(it->path().wstring())) + return it->path().wstring(); } return L""; }