Created
July 4, 2022 00:26
-
-
Save adinbied/eca8cfd233f14056002a4f139a38f855 to your computer and use it in GitHub Desktop.
Blackmagic SDK Extract Metadata Sample
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* -LICENSE-START- | |
** Copyright (c) 2018 Blackmagic Design | |
** | |
** Permission is hereby granted, free of charge, to any person or organization | |
** obtaining a copy of the software and accompanying documentation covered by | |
** this license (the "Software") to use, reproduce, display, distribute, | |
** execute, and transmit the Software, and to prepare derivative works of the | |
** Software, and to permit third-parties to whom the Software is furnished to | |
** do so, all subject to the following: | |
** | |
** The copyright notices in the Software and this entire statement, including | |
** the above license grant, this restriction and the following disclaimer, | |
** must be included in all copies of the Software, in whole or in part, and | |
** all derivative works of the Software, unless such copies or derivative | |
** works are solely in the form of machine-executable object code generated by | |
** a source language processor. | |
** | |
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT | |
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE | |
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, | |
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
** DEALINGS IN THE SOFTWARE. | |
** -LICENSE-END- | |
*/ | |
#include "BlackmagicRawAPIDispatch.h" | |
#include <cassert> | |
#include <atomic> | |
#include <iostream> | |
class CameraCodecCallback : public IBlackmagicRawCallback | |
{ | |
public: | |
explicit CameraCodecCallback() = default; | |
virtual ~CameraCodecCallback() | |
{ | |
assert(m_refCount == 0); | |
SetFrame(nullptr); | |
} | |
IBlackmagicRawFrame* GetFrame() { return m_frame; } | |
virtual void ReadComplete(IBlackmagicRawJob* readJob, HRESULT result, IBlackmagicRawFrame* frame) | |
{ | |
if (result == S_OK) | |
{ | |
SetFrame(frame); | |
} | |
} | |
virtual void ProcessComplete(IBlackmagicRawJob* job, HRESULT result, IBlackmagicRawProcessedImage* processedImage) {} | |
virtual void DecodeComplete(IBlackmagicRawJob*, HRESULT) {} | |
virtual void TrimProgress(IBlackmagicRawJob*, float) {} | |
virtual void TrimComplete(IBlackmagicRawJob*, HRESULT) {} | |
virtual void SidecarMetadataParseWarning(IBlackmagicRawClip*, BSTR, uint32_t, BSTR) {} | |
virtual void SidecarMetadataParseError(IBlackmagicRawClip*, BSTR, uint32_t, BSTR) {} | |
virtual void PreparePipelineComplete(void*, HRESULT) {} | |
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID*) | |
{ | |
return E_NOTIMPL; | |
} | |
virtual ULONG STDMETHODCALLTYPE AddRef(void) | |
{ | |
return ++m_refCount; | |
} | |
virtual ULONG STDMETHODCALLTYPE Release(void) | |
{ | |
const int32_t newRefValue = --m_refCount; | |
if (newRefValue == 0) | |
{ | |
delete this; | |
} | |
assert(newRefValue >= 0); | |
return newRefValue; | |
} | |
private: | |
void SetFrame(IBlackmagicRawFrame* frame) | |
{ | |
if (m_frame != nullptr) | |
m_frame->Release(); | |
m_frame = frame; | |
if (m_frame != nullptr) | |
m_frame->AddRef(); | |
} | |
IBlackmagicRawFrame* m_frame = nullptr; | |
std::atomic<int32_t> m_refCount = {0}; | |
}; | |
static void DumpMetadata(const char *header, IBlackmagicRawMetadataIterator* metadataIterator) | |
{ | |
BSTR key; | |
VARIANT value; | |
HRESULT result; | |
std::cout << std::endl << header << std::endl; | |
while (SUCCEEDED(metadataIterator->GetKey(&key))) | |
{ | |
std::wcout << key << ": "; | |
VariantInit(&value); | |
result = metadataIterator->GetData(&value); | |
if (result != S_OK) | |
{ | |
std::cerr << "Failed to get data from IBlackmagicRawMetadataIterator!" << std::endl; | |
break; | |
} | |
VARTYPE variantType = value.vt; | |
switch (variantType) | |
{ | |
case blackmagicRawVariantTypeS16: | |
{ | |
short s16 = value.iVal; | |
std::cout << s16; | |
} | |
break; | |
case blackmagicRawVariantTypeU16: | |
{ | |
unsigned short u16 = value.uiVal; | |
std::cout << u16; | |
} | |
break; | |
case blackmagicRawVariantTypeS32: | |
{ | |
int i32 = value.intVal; | |
std::cout << i32; | |
} | |
break; | |
case blackmagicRawVariantTypeU32: | |
{ | |
unsigned int u32 = value.uintVal; | |
std::cout << u32; | |
} | |
break; | |
case blackmagicRawVariantTypeFloat32: | |
{ | |
float f32 = value.fltVal; | |
std::cout << f32; | |
} | |
break; | |
case blackmagicRawVariantTypeString: | |
{ | |
BSTR bstr = value.bstrVal; | |
std::wcout << bstr; | |
} | |
break; | |
case blackmagicRawVariantTypeSafeArray: | |
{ | |
SafeArray* safeArray = value.parray; | |
void* safeArrayData = nullptr; | |
result = SafeArrayAccessData(safeArray, &safeArrayData); | |
if (result != S_OK) | |
{ | |
std::cerr << "Failed to access safeArray data!" << std::endl; | |
break; | |
} | |
VARTYPE arrayVarType; | |
result = SafeArrayGetVartype(safeArray, &arrayVarType); | |
if (result != S_OK) | |
{ | |
std::cerr << "Failed to get BlackmagicRawVariantType from safeArray!" << std::endl; | |
break; | |
} | |
long lBound; | |
result = SafeArrayGetLBound(safeArray, 1, &lBound); | |
if (result != S_OK) | |
{ | |
std::cerr << "Failed to get LBound from safeArray!" << std::endl; | |
break; | |
} | |
long uBound; | |
result = SafeArrayGetUBound(safeArray, 1, &uBound); | |
if (result != S_OK) | |
{ | |
std::cerr << "Failed to get UBound from safeArray!" << std::endl; | |
break; | |
} | |
long safeArrayLength = (uBound - lBound) + 1; | |
long arrayLength = safeArrayLength > 32 ? 32 : safeArrayLength; | |
for (int i = 0; i < arrayLength; ++i) | |
{ | |
switch (arrayVarType) | |
{ | |
case blackmagicRawVariantTypeU8: | |
{ | |
int u8 = static_cast<int>(static_cast<unsigned char*>(safeArrayData)[i]); | |
if (i > 0) | |
std::cout << ","; | |
std::cout << u8; | |
} | |
break; | |
case blackmagicRawVariantTypeS16: | |
{ | |
short s16 = static_cast<short*>(safeArrayData)[i]; | |
std::cout << s16 << ","; | |
} | |
break; | |
case blackmagicRawVariantTypeU16: | |
{ | |
unsigned short u16 = static_cast<unsigned short*>(safeArrayData)[i]; | |
std::cout << u16 << ","; | |
} | |
break; | |
case blackmagicRawVariantTypeS32: | |
{ | |
int i32 = static_cast<int*>(safeArrayData)[i]; | |
std::cout << i32 << ","; | |
} | |
break; | |
case blackmagicRawVariantTypeU32: | |
{ | |
unsigned int u32 = static_cast<unsigned int*>(safeArrayData)[i]; | |
std::cout << u32 << ","; | |
} | |
break; | |
case blackmagicRawVariantTypeFloat32: | |
{ | |
float f32 = static_cast<float*>(safeArrayData)[i]; | |
std::cout << f32 << ","; | |
} | |
break; | |
default: | |
break; | |
} | |
} | |
} | |
default: | |
break; | |
} | |
VariantClear(&value); | |
std::cout << std::endl; | |
metadataIterator->Next(); | |
} | |
} | |
int main(int argc, const char* argv[]) | |
{ | |
if (argc > 2) | |
{ | |
std::cerr << "Usage: " << argv[0] << " clipName.braw" << std::endl; | |
return 1; | |
} | |
BSTR clipName; | |
bool clipNameProvided = argc == 2; | |
if (clipNameProvided) | |
{ | |
const char* str = argv[1]; | |
int strLength = (int)strlen(str); | |
int wslen = MultiByteToWideChar(CP_ACP, 0, str, strLength, 0, 0); | |
clipName = SysAllocStringLen(0, wslen); | |
MultiByteToWideChar(CP_ACP, 0, argv[1], strLength, clipName, wslen); | |
} | |
else | |
{ | |
clipName = SysAllocString(L"C:\Program Files (x86)\Blackmagic Design\Blackmagic RAW\Blackmagic RAW SDK\Media\sample.braw"); | |
} | |
HRESULT result = S_OK; | |
IBlackmagicRawFactory* factory = nullptr; | |
IBlackmagicRaw* codec = nullptr; | |
IBlackmagicRawClip* clip = nullptr; | |
IBlackmagicRawMetadataIterator* clipMetadataIterator = nullptr; | |
IBlackmagicRawMetadataIterator* frameMetadataIterator = nullptr; | |
CameraCodecCallback* callback = nullptr; | |
do | |
{ | |
result = CoInitializeEx(nullptr, COINIT_MULTITHREADED); | |
if (result != S_OK) | |
{ | |
std::cerr << "Initialization of COM failed!" << std::endl; | |
break; | |
} | |
BSTR libraryPath = SysAllocString(L"../../Libraries"); | |
factory = CreateBlackmagicRawFactoryInstanceFromPath(libraryPath); | |
SysFreeString(libraryPath); | |
if (factory == nullptr) | |
{ | |
std::cerr << "Failed to create IBlackmagicRawFactory!" << std::endl; | |
break; | |
} | |
result = factory->CreateCodec(&codec); | |
if (result != S_OK) | |
{ | |
std::cerr << "Failed to create IBlackmagicRaw!" << std::endl; | |
break; | |
} | |
result = codec->OpenClip(clipName, &clip); | |
if (result != S_OK) | |
{ | |
std::cerr << "Failed to open IBlackmagicRawClip!" << std::endl; | |
break; | |
} | |
callback = new CameraCodecCallback(); | |
callback->AddRef(); | |
result = codec->SetCallback(callback); | |
if (result != S_OK) | |
{ | |
std::cerr << "Failed to set IBlackmagicRawCallback!" << std::endl; | |
break; | |
} | |
result = clip->GetMetadataIterator(&clipMetadataIterator); | |
if (result != S_OK) | |
{ | |
std::cerr << "Failed to get clip IBlackmagicRawMetadataIterator!" << std::endl; | |
break; | |
} | |
IBlackmagicRawJob* readJob = nullptr; | |
result = clip->CreateJobReadFrame(0, &readJob); | |
if (result != S_OK) | |
{ | |
std::cerr << "Failed to get IBlackmagicRawJob!" << std::endl; | |
break; | |
} | |
result = readJob->Submit(); | |
readJob->Release(); | |
if (result != S_OK) | |
{ | |
std::cerr << "Failed to submit IBlackmagicRawJob!" << std::endl; | |
break; | |
} | |
codec->FlushJobs(); | |
IBlackmagicRawFrame* frame = callback->GetFrame(); | |
if (frame == nullptr) | |
{ | |
std::cerr << "Failed to get IBlackmagicRawFrame!" << std::endl; | |
break; | |
} | |
result = frame->GetMetadataIterator(&frameMetadataIterator); | |
if (result != S_OK) | |
{ | |
std::cerr << "Failed to get frame IBlackmagicRawMetadataIterator!" << std::endl; | |
break; | |
} | |
DumpMetadata("Clip Metadata", clipMetadataIterator); | |
DumpMetadata("Frame 0 Metadata", frameMetadataIterator); | |
} while (0); | |
if (callback != nullptr) | |
callback->Release(); | |
if (clipMetadataIterator != nullptr) | |
clipMetadataIterator->Release(); | |
if (frameMetadataIterator != nullptr) | |
frameMetadataIterator->Release(); | |
if (clip != nullptr) | |
clip->Release(); | |
if (codec != nullptr) | |
codec->Release(); | |
if (factory != nullptr) | |
factory->Release(); | |
CoUninitialize(); | |
SysFreeString(clipName); | |
return result; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment