Skip to content

Instantly share code, notes, and snippets.

@irieger
Last active September 28, 2018 22:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save irieger/2eba5909c27b6cc195f6646a4cb12138 to your computer and use it in GitHub Desktop.
Save irieger/2eba5909c27b6cc195f6646a4cb12138 to your computer and use it in GitHub Desktop.
Blackmagic HDR metadata
IDeckLinkMutableVideoFrame* new_frame = NULL;
VideoFrameWithMetadata* frame_with_meta = nullptr;
result = this->_dl_video_output->CreateVideoFrame((int32_t)this->_width, (int32_t)this->_height, (int32_t) line_bytes, bmdFormat10BitRGB,bmdFrameFlagDefault, &new_frame);
if (result == S_OK)
{
new_frame->GetBytes((void**) &mem_ptr);
std::memset((void*) mem_ptr, 64, frame_bytes);
frame_with_meta = new VideoFrameWithMetadata(new_frame, false);
new_frame->Release();
this->_videoFrameBlack = frame_with_meta;
new_frame = NULL;
frame_with_meta = nullptr;
}
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include "videoframewithmetadata.h"
static inline bool CompareREFIID(const REFIID& ref1, const REFIID& ref2)
{
return memcmp(&ref1, &ref2, sizeof(REFIID)) == 0;
}
VideoFrameWithMetadata::VideoFrameWithMetadata(IDeckLinkVideoFrame* video_frame, bool activate_metadata)
: _video_frame(video_frame), _activate_metadata(activate_metadata), m_refCount(1)
{
this->_video_frame->AddRef();
}
VideoFrameWithMetadata::~VideoFrameWithMetadata()
{
this->_video_frame->Release();
}
HRESULT STDMETHODCALLTYPE VideoFrameWithMetadata::QueryInterface(REFIID iid, LPVOID *ppv)
{
if (CompareREFIID(iid, IID_IUnknown))
{
*ppv = static_cast<IDeckLinkVideoFrame*>(this);
}
else if (CompareREFIID(iid, IID_IDeckLinkVideoFrame))
{
*ppv = static_cast<IDeckLinkVideoFrame*>(this);
}
else if (CompareREFIID(iid, IID_IDeckLinkVideoFrameMetadataExtensions) && this->_activate_metadata)
{
*ppv = static_cast<IDeckLinkVideoFrameMetadataExtensions*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
ULONG STDMETHODCALLTYPE VideoFrameWithMetadata::AddRef(void)
{
// gcc atomic operation builtin
return __sync_add_and_fetch(&m_refCount, 1);
}
ULONG STDMETHODCALLTYPE VideoFrameWithMetadata::Release(void)
{
// gcc atomic operation builtin
ULONG newRefValue = __sync_sub_and_fetch(&m_refCount, 1);
if (!newRefValue)
delete this;
return newRefValue;
}
long VideoFrameWithMetadata::GetWidth(void)
{
return this->_video_frame->GetWidth();
}
long VideoFrameWithMetadata::GetHeight(void)
{
return this->_video_frame->GetHeight();
}
long VideoFrameWithMetadata::GetRowBytes(void)
{
return this->_video_frame->GetRowBytes();
}
BMDPixelFormat VideoFrameWithMetadata::GetPixelFormat(void)
{
return this->_video_frame->GetPixelFormat();
}
BMDFrameFlags VideoFrameWithMetadata::GetFlags(void)
{
if (this->_activate_metadata)
{
return bmdFrameContainsHDRMetadata;
}
else
{
return this->_video_frame->GetFlags();
}
}
HRESULT VideoFrameWithMetadata::GetBytes(/* out */ void** buffer)
{
return this->_video_frame->GetBytes(buffer);
}
HRESULT VideoFrameWithMetadata::GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode** timecode)
{
return this->_video_frame->GetTimecode(format, timecode);
}
HRESULT VideoFrameWithMetadata::GetAncillaryData (/* out */ IDeckLinkVideoFrameAncillary** ancillary)
{
return this->_video_frame->GetAncillaryData(ancillary);
}
HRESULT VideoFrameWithMetadata::GetInt (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ int64_t *value)
{
switch (metadataID)
{
case bmdDeckLinkFrameMetadataHDRElectroOpticalTransferFunc:
*value = this->_hdr_eotf;
break;
default:
return E_INVALIDARG;
}
return S_OK;
}
HRESULT VideoFrameWithMetadata::GetFloat (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ double *value)
{
switch (metadataID)
{
case bmdDeckLinkFrameMetadataHDRDisplayPrimariesRedX:
*value = this->_hdr_primary_red_x;
break;
case bmdDeckLinkFrameMetadataHDRDisplayPrimariesRedY:
*value = this->_hdr_primary_red_y;
break;
case bmdDeckLinkFrameMetadataHDRDisplayPrimariesGreenX:
*value = this->_hdr_primary_green_x;
break;
case bmdDeckLinkFrameMetadataHDRDisplayPrimariesGreenY:
*value = this->_hdr_primary_green_y;
break;
case bmdDeckLinkFrameMetadataHDRDisplayPrimariesBlueX:
*value = this->_hdr_primary_blue_x;
break;
case bmdDeckLinkFrameMetadataHDRDisplayPrimariesBlueY:
*value = this->_hdr_primary_blue_y;
break;
case bmdDeckLinkFrameMetadataHDRWhitePointX:
*value = this->_hdr_primary_white_x;
break;
case bmdDeckLinkFrameMetadataHDRWhitePointY:
*value = this->_hdr_primary_white_y;
break;
case bmdDeckLinkFrameMetadataHDRMaxDisplayMasteringLuminance:
*value = this->_hdr_max_master_disp_lum;
break;
case bmdDeckLinkFrameMetadataHDRMinDisplayMasteringLuminance:
*value = this->_hdr_min_master_disp_lum;
break;
case bmdDeckLinkFrameMetadataHDRMaximumContentLightLevel:
*value = this->_hdr_maximum_content_light_level;
break;
case bmdDeckLinkFrameMetadataHDRMaximumFrameAverageLightLevel:
*value = this->_hdr_maximum_average_frame_light_level;
break;
default:
return E_INVALIDARG;
}
return S_OK;
}
HRESULT VideoFrameWithMetadata::GetFlag (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ bool* value)
{
switch (metadataID)
{
default:
return E_INVALIDARG;
}
return S_OK;
}
HRESULT VideoFrameWithMetadata::GetString (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ const char **value)
{
switch (metadataID)
{
default:
return E_INVALIDARG;
}
return S_OK;
}
#include <DeckLinkAPI.h>
class VideoFrameWithMetadata : public IDeckLinkVideoFrame, public IDeckLinkVideoFrameMetadataExtensions
{
public:
VideoFrameWithMetadata(IDeckLinkVideoFrame* video_frame, bool activate_metadata = false);
~VideoFrameWithMetadata();
// IUnknown methods
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv);
virtual ULONG STDMETHODCALLTYPE AddRef(void);
virtual ULONG STDMETHODCALLTYPE Release(void);
// IDeckLinkVideoFrame methods
virtual long GetWidth(void);
virtual long GetHeight(void);
virtual long GetRowBytes(void);
virtual BMDPixelFormat GetPixelFormat(void);
virtual BMDFrameFlags GetFlags(void);
virtual HRESULT GetBytes(/* out */ void** buffer);
virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode** timecode) ;
virtual HRESULT GetAncillaryData (/* out */ IDeckLinkVideoFrameAncillary** ancillary);
// IDeckLinkVideoFrameMetadataExtensions
virtual HRESULT GetInt (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ int64_t *value);
virtual HRESULT GetFloat (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ double *value);
virtual HRESULT GetFlag (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ bool* value);
virtual HRESULT GetString (/* in */ BMDDeckLinkFrameMetadataID metadataID, /* out */ const char **value);
protected:
int32_t m_refCount;
IDeckLinkVideoFrame* _video_frame;
bool _activate_metadata = false;
int64_t _hdr_eotf = 2;
double _hdr_primary_red_x = 0.708;
double _hdr_primary_red_y = 0.292;
double _hdr_primary_green_x = 0.170;
double _hdr_primary_green_y = 0.797;
double _hdr_primary_blue_x = 0.131;
double _hdr_primary_blue_y = 0.046;
double _hdr_primary_white_x = 0.3127;
double _hdr_primary_white_y = 0.3290;
double _hdr_max_master_disp_lum = 4000.0;
double _hdr_min_master_disp_lum = 0.005;
double _hdr_maximum_content_light_level = 4000.0;
double _hdr_maximum_average_frame_light_level = 50.0;
};
@irieger
Copy link
Author

irieger commented Mar 11, 2018

Simple example based on TestPattern example from the blackmagic SDK (as suggested in their FAQ I used the VideoFrame3D sample code as a base. Not sure about correct cleanup implementation as I don't fully understand that part of their reference handling yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment