diff --git a/common/includes/IMediaSideData.h b/common/includes/IMediaSideData.h new file mode 100644 index 000000000..20d2ce5db --- /dev/null +++ b/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) diff --git a/decoder/LAVVideo/LAVVideo.cpp b/decoder/LAVVideo/LAVVideo.cpp index a8fa5779b..a310f1e69 100644 --- a/decoder/LAVVideo/LAVVideo.cpp +++ b/decoder/LAVVideo/LAVVideo.cpp @@ -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); diff --git a/decoder/LAVVideo/LAVVideo.h b/decoder/LAVVideo/LAVVideo.h index 7d53f05e9..418a0121c 100644 --- a/decoder/LAVVideo/LAVVideo.h +++ b/decoder/LAVVideo/LAVVideo.h @@ -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" diff --git a/decoder/LAVVideo/decoders/ILAVDecoder.h b/decoder/LAVVideo/decoders/ILAVDecoder.h index 07681826f..6269f8036 100644 --- a/decoder/LAVVideo/decoders/ILAVDecoder.h +++ b/decoder/LAVVideo/decoders/ILAVDecoder.h @@ -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 * @@ -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) @@ -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) diff --git a/decoder/LAVVideo/decoders/avcodec.cpp b/decoder/LAVVideo/decoders/avcodec.cpp index 71e4a10b4..81ded7ddd 100644 --- a/decoder/LAVVideo/decoders/avcodec.cpp +++ b/decoder/LAVVideo/decoders/avcodec.cpp @@ -26,6 +26,8 @@ #include "parsers/VC1HeaderParser.h" #include "Media.h" +#include "IMediaSideData.h" +#include "ByteParser.h" #ifdef DEBUG #include "lavf_log.h" @@ -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 { diff --git a/decoder/LAVVideo/decoders/pixfmt.cpp b/decoder/LAVVideo/decoders/pixfmt.cpp index cfd4e1d7a..576f5c9d3 100644 --- a/decoder/LAVVideo/decoders/pixfmt.cpp +++ b/decoder/LAVVideo/decoders/pixfmt.cpp @@ -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; } @@ -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; } @@ -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; +} diff --git a/ffmpeg b/ffmpeg index 9b3fcb882..86404ad13 160000 --- a/ffmpeg +++ b/ffmpeg @@ -1 +1 @@ -Subproject commit 9b3fcb8828d86a38e0f61aa6ae8be86c6408d8f8 +Subproject commit 86404ad13a2149600c04cc6023c25a29e480bca1