X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fproducer%2Futil.h;h=7b32ff9f0b1c090c8b1a0f7b7cc41e66239c4dcc;hb=ac7b3acb915f90de6b224e54a2240023fc221e5a;hp=501f7f8b72922a3fa90e79fa606291d34e1bad95;hpb=51cc844366d70779e17803ab721e23b62e9f9442;p=casparcg diff --git a/modules/ffmpeg/producer/util.h b/modules/ffmpeg/producer/util.h index 501f7f8b7..7b32ff9f0 100644 --- a/modules/ffmpeg/producer/util.h +++ b/modules/ffmpeg/producer/util.h @@ -1,237 +1,38 @@ #pragma once -#include -#include +#include +#include #include -#include -#include -#include -#if defined(_MSC_VER) -#pragma warning (push) -#pragma warning (disable : 4244) -#endif -extern "C" +extern "C" { - #include - #include - #include + #include } -#if defined(_MSC_VER) -#pragma warning (pop) -#endif -namespace caspar { - -static core::pixel_format::type get_pixel_format(PixelFormat pix_fmt) -{ - switch(pix_fmt) - { - case PIX_FMT_GRAY8: return core::pixel_format::gray; - case PIX_FMT_BGRA: return core::pixel_format::bgra; - case PIX_FMT_ARGB: return core::pixel_format::argb; - case PIX_FMT_RGBA: return core::pixel_format::rgba; - case PIX_FMT_ABGR: return core::pixel_format::abgr; - case PIX_FMT_YUV444P: return core::pixel_format::ycbcr; - case PIX_FMT_YUV422P: return core::pixel_format::ycbcr; - case PIX_FMT_YUV420P: return core::pixel_format::ycbcr; - case PIX_FMT_YUV411P: return core::pixel_format::ycbcr; - case PIX_FMT_YUV410P: return core::pixel_format::ycbcr; - case PIX_FMT_YUVA420P: return core::pixel_format::ycbcra; - default: return core::pixel_format::invalid; - } -} - -static PixelFormat get_ffmpeg_pixel_format(const core::pixel_format_desc& format_desc) -{ - switch(format_desc.pix_fmt) - { - case core::pixel_format::gray: return PIX_FMT_GRAY8; - case core::pixel_format::bgra: return PIX_FMT_BGRA; - case core::pixel_format::argb: return PIX_FMT_ARGB; - case core::pixel_format::rgba: return PIX_FMT_RGBA; - case core::pixel_format::abgr: return PIX_FMT_ABGR; - case core::pixel_format::ycbcra: return PIX_FMT_YUVA420P; - case core::pixel_format::ycbcr: - auto planes = format_desc.planes; - if(planes[0].height == planes[1].height) - { - if(planes[0].width == planes[1].width) - return PIX_FMT_YUV444P; - else if(planes[0].width/2 == planes[1].width) - return PIX_FMT_YUV422P; - else if(planes[0].width/4 == planes[1].width) - return PIX_FMT_YUV411P; - } - if(planes[0].height/2 == planes[1].height) - { - if(planes[0].width/2 == planes[1].width) - return PIX_FMT_YUV420P; - } - if(planes[0].height/4 == planes[1].height) - { - if(planes[0].width/4 == planes[1].width) - return PIX_FMT_YUV410P; - } - } - return PIX_FMT_NONE; -} - -static safe_ptr as_av_frame(const safe_ptr& frame) -{ - auto desc = frame->get_pixel_format_desc(); - safe_ptr av_frame(avcodec_alloc_frame(), av_free); - avcodec_get_frame_defaults(av_frame.get()); - - for(size_t n = 0; n < desc.planes.size(); ++n) - { - av_frame->data[n] = frame->image_data(n).begin(); - av_frame->linesize[n] = desc.planes[n].width; - } - - av_frame->format = get_ffmpeg_pixel_format(desc); - av_frame->width = desc.planes[0].width; - av_frame->height = desc.planes[0].height; +struct AVFrame; +struct AVFormatContext; - if(frame->get_type() != core::video_mode::progressive) - { - av_frame->interlaced_frame = 1; - av_frame->top_field_first = frame->get_type() == core::video_mode::upper ? 1 : 0; - } - - return av_frame; -} - -static core::pixel_format_desc get_pixel_format_desc(PixelFormat pix_fmt, size_t width, size_t height) -{ - // Get linesizes - AVPicture dummy_pict; - avpicture_fill(&dummy_pict, nullptr, pix_fmt, width, height); +namespace caspar { - core::pixel_format_desc desc; - desc.pix_fmt = get_pixel_format(pix_fmt); - - switch(desc.pix_fmt) - { - case core::pixel_format::gray: - { - desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[0]/4, height, 1)); - return desc; - } - case core::pixel_format::bgra: - case core::pixel_format::argb: - case core::pixel_format::rgba: - case core::pixel_format::abgr: - { - desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[0]/4, height, 4)); - return desc; - } - case core::pixel_format::ycbcr: - 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]; +namespace core { - 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)); +struct pixel_format_desc; +class write_frame; +struct frame_factory; - if(desc.pix_fmt == 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; - return desc; - } } -static safe_ptr make_write_frame(const void* tag, const safe_ptr& decoded_frame, const safe_ptr& frame_factory) -{ - static tbb::concurrent_unordered_map>> sws_contexts_; - - auto width = decoded_frame->width; - auto height = decoded_frame->height; - auto pix_fmt = static_cast(decoded_frame->format); - auto desc = get_pixel_format_desc(pix_fmt, width, height); - - auto write = frame_factory->create_frame(tag, desc.pix_fmt != core::pixel_format::invalid ? desc : get_pixel_format_desc(PIX_FMT_BGRA, width, height)); - if(decoded_frame->interlaced_frame) - write->set_type(decoded_frame->top_field_first ? core::video_mode::upper : core::video_mode::lower); - else - write->set_type(core::video_mode::progressive); +namespace ffmpeg { - if(desc.pix_fmt == core::pixel_format::invalid) - { - std::shared_ptr sws_context; +static const PixelFormat CASPAR_PIX_FMT_LUMA = PIX_FMT_MONOBLACK; // Just hijack some unual pixel format. - //CASPAR_LOG(warning) << "Hardware accelerated color transform not supported."; +core::field_mode::type get_mode(AVFrame& frame); +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); +int make_alpha_format(int format); // NOTE: Be careful about CASPAR_PIX_FMT_LUMA, change it to PIX_FMT_GRAY8 if you want to use the frame inside some ffmpeg function. +safe_ptr make_write_frame(const void* tag, const safe_ptr& decoded_frame, const safe_ptr& frame_factory, int hints); - size_t key = width << 20 | height << 8 | pix_fmt; - - auto& pool = sws_contexts_[key]; - - if(!pool.try_pop(sws_context)) - { - double param; - sws_context.reset(sws_getContext(width, height, pix_fmt, width, height, PIX_FMT_BGRA, SWS_BILINEAR, nullptr, nullptr, ¶m), sws_freeContext); - } - - if(!sws_context) - { - BOOST_THROW_EXCEPTION(operation_failed() << msg_info("Could not create software scaling context.") << - boost::errinfo_api_function("sws_getContext")); - } - - // Use sws_scale when provided colorspace has no hw-accel. - safe_ptr av_frame(avcodec_alloc_frame(), av_free); - avcodec_get_frame_defaults(av_frame.get()); - avpicture_fill(reinterpret_cast(av_frame.get()), write->image_data().begin(), PIX_FMT_BGRA, width, height); - - sws_scale(sws_context.get(), decoded_frame->data, decoded_frame->linesize, 0, height, av_frame->data, av_frame->linesize); - pool.push(sws_context); - - write->commit(); - } - else - { - tbb::parallel_for(0, static_cast(desc.planes.size()), 1, [&](int n) - { - auto plane = desc.planes[n]; - auto result = write->image_data(n).begin(); - auto decoded = decoded_frame->data[n]; - auto decoded_linesize = decoded_frame->linesize[n]; - - // Copy line by line since ffmpeg sometimes pads each line. - tbb::parallel_for(tbb::blocked_range(0, static_cast(desc.planes[n].height)), [&](const tbb::blocked_range& r) - { - for(size_t y = r.begin(); y != r.end(); ++y) - memcpy(result + y*plane.linesize, decoded + y*decoded_linesize, plane.linesize); - }); - - write->commit(n); - }); - } - - // Fix field-order if needed - if(decoded_frame->interlaced_frame) - { - switch(frame_factory->get_video_format_desc().mode) - { - case core::video_mode::upper: - if(!decoded_frame->top_field_first) - write->get_image_transform().set_fill_translation(0.0f, 0.5/static_cast(height)); - break; - case core::video_mode::lower: - if(decoded_frame->top_field_first) - write->get_image_transform().set_fill_translation(0.0f, -0.5/static_cast(height)); - break; - } - } - - return write; -} +void fix_meta_data(AVFormatContext& context); -} \ No newline at end of file +}} \ No newline at end of file