Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for higher precision pixel formats #1528

Merged
merged 22 commits into from
May 24, 2024

Conversation

niklaspandersson
Copy link
Member

This branch introduces:

  • Required plumbing in accelerator / core / common / shell for managing frames with a higher than 8 bit precision pixel format
  • Basic support in ffmpeg producer for preserving precision of 10- and 12 bit content
  • Rudimentary support in the ffmpeg- and decklink consumers for consuming higher precision frames

Only minimal testing have been performed on windows.

Copy link
Member

@Julusian Julusian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a good start, and doesn't architecturally conflict with what I had in mind.
It is rather minimal in what producers/consumers are supported, but I don't see that as a problem for now.

The only bit I don't like is the comment I added in array.h

src/common/array.h Outdated Show resolved Hide resolved
src/modules/decklink/consumer/frame.cpp Show resolved Hide resolved
src/modules/decklink/consumer/frame.cpp Show resolved Hide resolved
@@ -502,7 +502,11 @@ struct Filter
AV_PIX_FMT_ABGR,
AV_PIX_FMT_YUV444P,
AV_PIX_FMT_YUV422P,
AV_PIX_FMT_YUV422P10,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this could include more formats?
In my testing, some codecs prefered to decode to RGB48/RGBA64, which should be trivial to handle.
And I was able to add the following yuv formats which I think only needed the handling on mapping into pixel_format:

                                              AV_PIX_FMT_YUV444P10,
                                              AV_PIX_FMT_YUV422P10,
                                              AV_PIX_FMT_YUV420P10,
                                              AV_PIX_FMT_YUV444P16,
                                              AV_PIX_FMT_YUV422P16,
                                              AV_PIX_FMT_YUV420P16,
                                              AV_PIX_FMT_YUVA444P10,
                                              AV_PIX_FMT_YUVA422P10,
                                              AV_PIX_FMT_YUVA420P10,
                                              AV_PIX_FMT_YUVA444P16,
                                              AV_PIX_FMT_YUVA422P16,
                                              AV_PIX_FMT_YUVA420P16,

This isn't necessary for merging this PR though.

});
}

#ifdef WIN32
std::future<std::shared_ptr<texture>> copy_async(GLuint source, int width, int height, int stride)
/* Unused? */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I forgot to remove this when removing the shared-texture flow for CEF. Feel free to delete it

src/accelerator/ogl/image/image_kernel.cpp Show resolved Hide resolved
{
configuration config = parse_xml_config(ptree, format_repository);

config.hdr = (depth != common::bit_depth::bit8);

if (config.hdr && config.primary.has_subregion_geometry()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a shame, but I can appreciate that making all of these features behave correctly with 16bit will be hard and is not being asked for yet.
Unfortunately this means that it won't be possible to benefit from this work if a key output is needed, so this will only be usable in fullscreen channels, rather than keyed overlay channels. (This is not a problem, just writing out this limitation for when other users are curious)

@niklaspandersson
Copy link
Member Author

I'm glad that you approve. This is just the first iteration, to get something out there that can be tested by the client. How "complete" the support will be will ultimately be up to them.

@5opr4ni
Copy link
Contributor

5opr4ni commented Apr 8, 2024

Hi,

This is super interesting work and would have been very useful for Eurovision Song Contest 2024 in Malmö, where we're incorporating a lot of color gradients in the graphics. All the graphics for ESC will be done in CasparCG.

Keep up the good work, Niklas and Julian!

@MauriceVeraart
Copy link
Contributor

Nice work. Can this also be used for "custom resolution consumers"?
10Bit or even higher will be a big improvement for our market with non-standard resolutions. 

@@ -225,6 +225,8 @@ struct HDRMetadata
const auto REC_709 = ChromaticityCoordinates{0.640, 0.330, 0.300, 0.600, 0.150, 0.060, 0.3127, 0.3290};
const auto REC_2020 = ChromaticityCoordinates{0.708, 0.292, 0.170, 0.797, 0.131, 0.046, 0.3127, 0.3290};

typedef const char* BSTR;
Copy link
Member

@Julusian Julusian Apr 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Theres already an typedef called String inside decklink_api.h which handles this abstraction.
So replace the uses of BSTR with String and it should be happy

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that's great! Thank you

@niklaspandersson niklaspandersson force-pushed the 16bit branch 2 times, most recently from e323e81 to e8d8e88 Compare April 24, 2024 10:58
@niklaspandersson niklaspandersson marked this pull request as ready for review April 29, 2024 08:39
src/accelerator/ogl/image/image_kernel.cpp Show resolved Hide resolved
src/modules/decklink/producer/decklink_producer.cpp Outdated Show resolved Hide resolved
src/modules/ffmpeg/producer/av_producer.cpp Outdated Show resolved Hide resolved
@@ -255,15 +257,27 @@ struct server::impl

auto format_desc_str = xml_channel.second.get(L"video-mode", L"PAL");
auto format_desc = video_format_repository_.find(format_desc_str);
auto color_depth = xml_channel.second.get<unsigned char>(L"color-depth", 8);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following what this color_depth value is actually used for.
As far I can tell, it is being passed around a lot to then be only used by https://github.com/niklaspandersson/casparcg-server/blob/aac7d44da5e25613efd1a0ffcb53892a45062d8a/src/core/mixer/mixer.cpp#L77-L87, but does that need/want a color_space as at that point it is RGB?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used to determine whether to use one or two bytes per color channel in mixer-generated frames. It's needed to maintain the extra precision throughout the pipeline.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, I meant to write this on the color-space parsing, not color-depth

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frames created by the mixer need to be tagged with an explicit color space for consumers such as decklink to be able to attach the correct metadata on their output.
It is also needed to perform correct color space transformations in the mixer when combining material from different color spaces (not implemented yet though)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is also needed to perform correct color space transformations in the mixer when combining material from different color spaces (not implemented yet though)

I wouldn't expect that to be necessary, seeing how the output of the shader is rgb. So while frames may enter the mixer as different formats in varying color spaces, the output should always be rgb and surely agnostic of whatever the output color space will be?

Frames created by the mixer need to be tagged with an explicit color space for consumers such as decklink to be able to attach the correct metadata on their output.

I would expect this to be a property of the consumer, not the whole channel.


I haven't done much research into how HDR and its metadata works, but from what I have read I would expect that the only changes needed are to:

  1. composite in 16bit rgb
  2. use the correct algorithm for converting that to 10bit yuv using the chosen hdr mode and metadata values

so unless the mixer is going to be generating frames in yuv, does it need to know what the consumers are doing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RGB is not color space agnostic. Max green, ie. vec3(0, 1.0, 0), represents different shades of green depending on which color space you're using.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right. Having looked into it some more, you are right.
Sometimes referred to as wide and narrow gamut.

I'm still not entirely keen on this being done on the channel like this, but I dont have any better ideas right now. Especially as there isn't a convenient/cheap place to do a per-consumer color conversion

src/accelerator/ogl/util/device.cpp Outdated Show resolved Hide resolved
@niklaspandersson
Copy link
Member Author

@MauriceVeraart

Nice work. Can this also be used for "custom resolution consumers"? 10Bit or even higher will be a big improvement for our market with non-standard resolutions.

Yes, absolutely. For ffmpeg I think it would just work without any modifications. Do have a specific consumer in mind?

@MauriceVeraart
Copy link
Contributor

@MauriceVeraart

Nice work. Can this also be used for "custom resolution consumers"? 10Bit or even higher will be a big improvement for our market with non-standard resolutions.

Yes, absolutely. For ffmpeg I think it would just work without any modifications. Do have a specific consumer in mind?

When we use custom resolutions it will be the screenconsumer

@Julusian
Copy link
Member

@niklaspandersson I don't see any comments left that need addressing on this. Let me know if you are happy for it to be merged (or go ahead and merge it yourself)

@niklaspandersson
Copy link
Member Author

@Julusian I'm happy if you are happy. Feel free to merge

@Julusian Julusian merged commit 2ffc202 into CasparCG:master May 24, 2024
4 checks passed
@Sidonai-1
Copy link

Great work, thank you!

Question: channel bit depth goes from 8 to 16 directly, right? I tried to set it to 10 or 12 but it crashed, I just wanted to quickly test it on a laptop without decklink to compare image outputs with Photoshop but it seems that is not possible at the moment.

Screen consumer only supports 8-bit color depth
Image consumer only supports 8-bit color depth.

@Julusian
Copy link
Member

@Sidonai-1 correct, it is limited to 8 or 16bit
And yes, the consumer/producer support for higher bit depths is very limited currently

@Sidonai-1
Copy link

Nice work. Can this also be used for "custom resolution consumers"? 10Bit or even higher will be a big improvement for our market with non-standard resolutions.

I guess when the screen consumer gets upgraded @MauriceVeraart you will be able to feed large VW at 10 bit, do you use Windows? Does it handle the screen consumer properly and in sync with the audio? I never used it for production because the frame-time was all over the place so it was not very smooth, specially comparing to Decklink.
I wonder how well will Windows maintain the 10bit consumer, maybe with some extra configuration in the GPU settings?

I wanted to see if a 16bit channel would work as it is with custom resolutions and decklink ports but I got an error:

[2024-06-17 16:29:38.702] [error]   Exception: D:\a\server\server\src\modules\decklink\consumer\decklink_consumer.cpp(1131): Throw in function class caspar::spl::shared_ptr<class caspar::core::frame_consumer> __cdecl caspar::decklink::create_preconfigured_consumer(const class boost::property_tree::basic_ptree<class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> >,class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> >,struct std::less<class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> > > > &,const class caspar::core::video_format_repository &,const class std::vector<class caspar::spl::shared_ptr<class caspar::core::video_channel>,class std::allocator<class caspar::spl::shared_ptr<class caspar::core::video_channel> > > &,enum caspar::common::bit_depth)
[2024-06-17 16:29:38.702] [error]   Dynamic exception type: class boost::exception_detail::clone_impl<struct caspar::caspar_exception>
[2024-06-17 16:29:38.702] [error]   [struct caspar::tag_msg_info * __ptr64] = Decklink consumer does not support hdr in combination with secondary ports.
[2024-06-17 16:29:38.702] [error]   [struct caspar::tag_stacktrace_info * __ptr64] =  0# 0x00007FF7DF283427 in casparcg
[2024-06-17 16:29:38.702] [error]    1# 0x00007FF7DF2AF7C6 in casparcg
[2024-06-17 16:29:38.702] [error]    2# 0x00007FF7DF407EA0 in casparcg
[2024-06-17 16:29:38.702] [error]    3# 0x00007FF7DF3C0041 in casparcg
[2024-06-17 16:29:38.702] [error]    4# 0x00007FF7DF30FC7C in casparcg
[2024-06-17 16:29:38.702] [error]    5# 0x00007FF7DF310254 in casparcg
[2024-06-17 16:29:38.702] [error]    6# 0x00007FF7DF2AAEBA in casparcg
[2024-06-17 16:29:38.702] [error]    7# 0x00007FF7DF2AFD4B in casparcg
[2024-06-17 16:29:38.702] [error]    8# 0x00007FF7DF2850C8 in casparcg
[2024-06-17 16:29:38.702] [error]    9# 0x00007FF7DF2883FF in casparcg
[2024-06-17 16:29:38.702] [error]   10# 0x00007FF7DF4F5B64 in casparcg
[2024-06-17 16:29:38.702] [error]   11# BaseThreadInitThunk in KERNEL32
[2024-06-17 16:29:38.702] [error]   12# RtlUserThreadStart in ntdll
[2024-06-17 16:29:38.702] [error]   
[2024-06-17 16:29:38.702] [error]   
[2024-06-17 16:29:38.702] [error]    0# 0x00007FF7DF283427 in casparcg
[2024-06-17 16:29:38.702] [error]    1# 0x00007FF7DF282EAA in casparcg
[2024-06-17 16:29:38.702] [error]    2# 0x00007FF7DF5390D9 in casparcg
[2024-06-17 16:29:38.702] [error]    3# 0x00007FF8CE271080 in VCRUNTIME140_1
[2024-06-17 16:29:38.702] [error]    4# _NLG_Return2 in VCRUNTIME140_1
[2024-06-17 16:29:38.702] [error]    5# RtlCaptureContext2 in ntdll
[2024-06-17 16:29:38.702] [error]    6# 0x00007FF7DF2AAEBA in casparcg
[2024-06-17 16:29:38.702] [error]    7# 0x00007FF7DF2AFD4B in casparcg
[2024-06-17 16:29:38.702] [error]    8# 0x00007FF7DF2850C8 in casparcg
[2024-06-17 16:29:38.702] [error]    9# 0x00007FF7DF2883FF in casparcg
[2024-06-17 16:29:38.702] [error]   10# 0x00007FF7DF4F5B64 in casparcg
[2024-06-17 16:29:38.702] [error]   11# BaseThreadInitThunk in KERNEL32
[2024-06-17 16:29:38.702] [error]   12# RtlUserThreadStart in ntdll

I wonder if "Decklink consumer does not support hdr in combination with secondary ports." comes from a SDK limitation or it's just not fully implemented yet. Hopefully it's the latter 😁

It was a bit strange that the log was complaining about HDR. The channel was set at 16bit in the config, with no color space or HDR settings specified.

I thought bit depth and HDR on/off were be 'independent' in some way. Are they completely intertwined?

Thanks.

@niklaspandersson niklaspandersson deleted the 16bit branch September 23, 2024 11:19
jpc0 pushed a commit to jpc0/server that referenced this pull request Oct 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants