Skip to content

Commit

Permalink
Export HEVC HDR metadata to the renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
Nevcairiel committed Dec 7, 2015
1 parent 29c988c commit 499aca4
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 1 deletion.
45 changes: 45 additions & 0 deletions common/includes/IMediaSideData.h
@@ -0,0 +1,45 @@
// -----------------------------------------------------------------
// IMediaSideData interface and data structure definitions
// -----------------------------------------------------------------

#pragma once

// -----------------------------------------------------------------
// Interface to exchange binary side data
// -----------------------------------------------------------------
// This interface should be implemented in IMediaSample objects and accessed through IUnknown
// It allows binary side data to be attached to the media samples and delivered with them
// Restrictions: Only one side data per type can be attached
[uuid("F940AE7F-48EB-4377-806C-8FC48CAB2292")]
interface IMediaSideData : public IUnknown
{
// Set the side data identified by guidType to the data provided
// The provided data will be copied and stored internally
STDMETHOD(SetSideData)(GUID guidType, const BYTE *pData, size_t size) PURE;

// Get the side data identified by guidType
// The caller receives pointers to the internal data, and the pointers shall stay
// valid for the lifetime of the object
STDMETHOD(GetSideData)(GUID guidType, const BYTE **pData, size_t *pSize) PURE;
};


// -----------------------------------------------------------------
// High-Dynamic-Range (HDR) Side Data
// -----------------------------------------------------------------

// {53820DBC-A7B8-49C4-B17B-E511591A790C}
DEFINE_GUID(IID_MediaSideDataHDR,
0x53820dbc, 0xa7b8, 0x49c4, 0xb1, 0x7b, 0xe5, 0x11, 0x59, 0x1a, 0x79, 0xc);

#pragma pack(push, 1)
struct MediaSideDataHDR
{
double display_primaries_x[3];
double display_primaries_y[3];
double white_point_x;
double white_point_y;
double max_display_mastering_luminance;
double min_display_mastering_luminance;
};
#pragma pack(pop)
9 changes: 9 additions & 0 deletions decoder/LAVVideo/LAVVideo.cpp
Expand Up @@ -1658,6 +1658,15 @@ HRESULT CLAVVideo::DeliverToRenderer(LAVFrame *pFrame)
DbgLog((LOG_TRACE, 10, L"Pixel Mapping took %2.3fms in avg", m_pixFmtTimingAvg.Average()));
#endif

// Set side data on the media sample
if (pFrame->side_data_count) {
IMediaSideData *pMediaSideData = nullptr;
if (SUCCEEDED(hr = pSampleOut->QueryInterface(&pMediaSideData))) {
for (int i = 0; i < pFrame->side_data_count; i++)
pMediaSideData->SetSideData(pFrame->side_data[i].guidType, pFrame->side_data[i].data, pFrame->side_data[i].size);
}
}

// Once we're done with the old frame, release its buffers
// This does not release the frame yet, just free its buffers
FreeLAVFrameBuffers(pFrame);
Expand Down
1 change: 1 addition & 0 deletions decoder/LAVVideo/LAVVideo.h
Expand Up @@ -34,6 +34,7 @@
#include "subtitles/LAVVideoSubtitleInputPin.h"

#include "BaseTrayIcon.h"
#include "IMediaSideData.h"

#define LAVC_VIDEO_REGISTRY_KEY L"Software\\LAV\\Video"
#define LAVC_VIDEO_REGISTRY_KEY_FORMATS L"Software\\LAV\\Video\\Formats"
Expand Down
14 changes: 14 additions & 0 deletions decoder/LAVVideo/decoders/ILAVDecoder.h
Expand Up @@ -83,6 +83,12 @@ typedef struct LAVDirectBuffer {
ptrdiff_t stride[4]; ///< stride of the planes (in bytes)
} LAVDirectBuffer;

typedef struct LAVFrameSideData {
GUID guidType; ///< type of the side data
BYTE *data; ///< side data
size_t size; ///< size
} LAVFrameSideData;

/**
* A Video Frame
*
Expand Down Expand Up @@ -125,6 +131,9 @@ typedef struct LAVFrame {
#define LAV_FRAME_FLAG_REDRAW 0x00000008
#define LAV_FRAME_FLAG_DXVA_NOADDREF 0x00000010

LAVFrameSideData *side_data;
int side_data_count;

/* destruct function to free any buffers being held by this frame (may be null) */
void (*destruct)(struct LAVFrame *);
void *priv_data; ///< private data from the decoder (mostly for destruct)
Expand Down Expand Up @@ -163,6 +172,11 @@ HRESULT CopyLAVFrame(LAVFrame *pSrc, LAVFrame **ppDst);
*/
HRESULT CopyLAVFrameInPlace(LAVFrame *pFrame);

/**
* Add Side Data to the frame and return a pointer to it
*/
BYTE * AddLAVFrameSideData(LAVFrame *pFrame, GUID guidType, size_t size);

typedef struct LAVPinInfo
{
DWORD flags; ///< Flags that describe the video content (see ILAVPinInfo.h for valid values)
Expand Down
24 changes: 24 additions & 0 deletions decoder/LAVVideo/decoders/avcodec.cpp
Expand Up @@ -26,6 +26,8 @@
#include "parsers/VC1HeaderParser.h"

#include "Media.h"
#include "IMediaSideData.h"
#include "ByteParser.h"

#ifdef DEBUG
#include "lavf_log.h"
Expand Down Expand Up @@ -903,6 +905,28 @@ STDMETHODIMP CDecAvcodec::Decode(const BYTE *buffer, int buflen, REFERENCE_TIME
if (m_nCodecId == AV_CODEC_ID_MPEG2VIDEO || m_nCodecId == AV_CODEC_ID_MPEG1VIDEO)
pOutFrame->avgFrameDuration = GetFrameDuration();

AVFrameSideData * sdHDR = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_HDR_MASTERING_INFO);
if (sdHDR) {
if (sdHDR->size == 24) {
MediaSideDataHDR * hdr = (MediaSideDataHDR *)AddLAVFrameSideData(pOutFrame, IID_MediaSideDataHDR, sizeof(MediaSideDataHDR));
if (hdr) {
CByteParser hdrParser(sdHDR->data, sdHDR->size);
for (int i = 0; i < 3; i++)
{
hdr->display_primaries_x[i] = hdrParser.BitRead(16) * 0.00002;
hdr->display_primaries_y[i] = hdrParser.BitRead(16) * 0.00002;
}
hdr->white_point_x = hdrParser.BitRead(16) * 0.00002;
hdr->white_point_y = hdrParser.BitRead(16) * 0.00002;
hdr->max_display_mastering_luminance = hdrParser.BitRead(32) * 0.0001;
hdr->min_display_mastering_luminance = hdrParser.BitRead(32) * 0.0001;
}
}
else {
DbgLog((LOG_TRACE, 10, L"::Decode(): Found HDR data of an unexpected size (%d)", sdHDR->size));
}
}

if (map.conversion) {
ConvertPixFmt(m_pFrame, pOutFrame);
} else {
Expand Down
36 changes: 36 additions & 0 deletions decoder/LAVVideo/decoders/pixfmt.cpp
Expand Up @@ -132,6 +132,14 @@ HRESULT FreeLAVFrameBuffers(LAVFrame *pFrame)
}
memset(pFrame->data, 0, sizeof(pFrame->data));
memset(pFrame->stride, 0, sizeof(pFrame->stride));

for (int i = 0; i < pFrame->side_data_count; i++)
{
SAFE_CO_FREE(pFrame->side_data[i].data);
}
SAFE_CO_FREE(pFrame->side_data);
pFrame->side_data_count = 0;

return S_OK;
}

Expand Down Expand Up @@ -161,6 +169,15 @@ HRESULT CopyLAVFrame(LAVFrame *pSrc, LAVFrame **ppDst)
}
}

(*ppDst)->side_data = nullptr;
(*ppDst)->side_data_count = 0;
for (int i = 0; i < pSrc->side_data_count; i++)
{
BYTE * p = AddLAVFrameSideData(*ppDst, pSrc->side_data[i].guidType, pSrc->side_data[i].size);
if (p)
memcpy(p, pSrc->side_data[i].data, pSrc->side_data[i].size);
}

return S_OK;
}

Expand All @@ -173,3 +190,22 @@ HRESULT CopyLAVFrameInPlace(LAVFrame *pFrame)
SAFE_CO_FREE(tmpFrame);
return S_OK;
}

BYTE * AddLAVFrameSideData(LAVFrame *pFrame, GUID guidType, size_t size)
{
BYTE * ptr = (BYTE *)CoTaskMemRealloc(pFrame->side_data, sizeof(LAVFrameSideData) * (pFrame->side_data_count + 1));
if (!ptr)
return NULL;

pFrame->side_data = (LAVFrameSideData *)ptr;
pFrame->side_data[pFrame->side_data_count].guidType = guidType;
pFrame->side_data[pFrame->side_data_count].data = (BYTE *)CoTaskMemAlloc(size);
pFrame->side_data[pFrame->side_data_count].size = size;

if (!pFrame->side_data[pFrame->side_data_count].data)
return NULL;

pFrame->side_data_count++;

return pFrame->side_data[pFrame->side_data_count - 1].data;
}
2 changes: 1 addition & 1 deletion ffmpeg
Submodule ffmpeg updated from 9b3fcb to 86404a

0 comments on commit 499aca4

Please sign in to comment.