Skip to content

Instantly share code, notes, and snippets.

@Stehfyn
Last active July 26, 2025 19:52
Show Gist options
  • Select an option

  • Save Stehfyn/96296a3c33033f852794f8a5bcbf3034 to your computer and use it in GitHub Desktop.

Select an option

Save Stehfyn/96296a3c33033f852794f8a5bcbf3034 to your computer and use it in GitHub Desktop.
#include "video.h"
#define __STDC_CONSTANT_MACROS //do we need?
#include "libavutil/imgutils.h"
//#include "lavfutils.h"
#include <libavformat/avformat.h>
#include "stdafx.h"
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavcodec/codec_id.h>
#include <libavutil/pixfmt.h>
#include <inttypes.h>
#include <libavutil/avassert.h>
typedef enum AVPixelFormat AVPixelFormat;
typedef struct SwsContext SwsContext;
struct D2DVideoDecoder
{
int width;
int height;
float pts;
double fps;
AVRational TimeBase;
AVFormatContext* pAVFormatContext;
AVCodecContext* pAVCodecContext;
int nVideoStreamIdx;
AVFrame* pAVFrame;
AVFrame* pAVFrameOut;
AVPacket* pAVPacket;
SwsContext* pSwsContext;
};
static AVPixelFormat EnsurePixelFormat(AVPixelFormat pix_fmt)
{
// Fix swscaler deprecated pixel format warning
// (YUVJ has been deprecated, change pixel format to regular YUV)
switch (pix_fmt) {
case AV_PIX_FMT_YUVJ420P: return AV_PIX_FMT_YUV420P;
case AV_PIX_FMT_YUVJ422P: return AV_PIX_FMT_YUV422P;
case AV_PIX_FMT_YUVJ444P: return AV_PIX_FMT_YUV444P;
case AV_PIX_FMT_YUVJ440P: return AV_PIX_FMT_YUV440P;
default: return pix_fmt;
}
}
static void CpuDecodeFrame(AVCodecContext* pCodecContext, AVPacket* pAVPacket, AVFrame* pAVFrameDemuxed, AVFrame* pAVFrameDecoded, SwsContext* pSwsContext)
{
int ret;
ret = avcodec_send_packet(pCodecContext, (const AVPacket*)pAVPacket);
av_assert0(0 == ret);
while (0 <= ret)
{
ret = avcodec_receive_frame(pCodecContext, pAVFrameDemuxed);
if (0 > ret)
{
switch (ret) {
case AVERROR(EAGAIN):
av_frame_unref(pAVFrameDemuxed);
case AVERROR_EOF:
av_packet_unref(pAVPacket);
return;
default:
av_assert0(0);
}
}
// TODO: Exec Callback here with data plus ret info
ret = sws_scale(
pSwsContext,
pAVFrameDemuxed->data,
pAVFrameDemuxed->linesize,
0,
pAVFrameDemuxed->height,
pAVFrameDecoded->data,
pAVFrameDecoded->linesize
);
}
}
HRESULT ID2DVideoDecoder_Create(ID2DVideoDecoder** pThis)
{
//(*pThis) = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ID2DVideoDecoder));
(*pThis) = av_mallocz(sizeof(ID2DVideoDecoder));
return (!!(*pThis)) ? S_OK : E_FAIL;
}
HRESULT ID2DVideoDecoder_OpenVideo(ID2DVideoDecoder* pThis, const char* file, INT32* pFileOpen)
{
AVCodec* pAVCodec;
AVStream** ppAVStream;
AVCodecParameters* pAVCodecParameters;
int nStreamIdx;
int ret;
if (pThis->pAVFormatContext)
{
ID2DVideoDecoder_CloseVideo(pThis);
}
pThis->pAVFormatContext = avformat_alloc_context();
if (!pThis->pAVFormatContext)
return E_FAIL;
if (0 > avformat_open_input(&pThis->pAVFormatContext, file, 0, 0))
return E_FAIL;
if (0 > avformat_find_stream_info(pThis->pAVFormatContext, 0))
return E_FAIL;
pAVCodec = (AVCodec*)1;
ret = av_find_best_stream(pThis->pAVFormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, &pAVCodec, 0);
if (0 > ret)
{
switch (ret) {
case AVERROR_STREAM_NOT_FOUND:
av_log(0, AV_LOG_FATAL, av_err2str(AVERROR_STREAM_NOT_FOUND));
break;
case AVERROR_DECODER_NOT_FOUND:
av_log(0, AV_LOG_FATAL, av_err2str(AVERROR_DECODER_NOT_FOUND));
break;
}
return E_FAIL;
}
nStreamIdx = ret;
ppAVStream = pThis->pAVFormatContext->streams[nStreamIdx];
pThis->fps = (double)(*ppAVStream)->r_frame_rate.num / (double)(*ppAVStream)->r_frame_rate.den;
pThis->nVideoStreamIdx = -1;
pAVCodecParameters = 0;
for (nStreamIdx = 0; nStreamIdx < pThis->pAVFormatContext->nb_streams; ++nStreamIdx)
{
AVStream* pAVStream;
pAVStream = pThis->pAVFormatContext->streams[nStreamIdx];
if (AVMEDIA_TYPE_VIDEO == pAVStream->codecpar->codec_type)
{
pAVCodecParameters = pAVStream->codecpar;
pAVCodec = (AVCodec*)avcodec_find_decoder(pAVCodecParameters->codec_id);
if (!pAVCodec)
{
// TODO: Really handle this find failure
continue;
}
pThis->nVideoStreamIdx = nStreamIdx;
pThis->width = pAVCodecParameters->width;
pThis->height = pAVCodecParameters->height;
pThis->TimeBase = pAVStream->time_base;
}
}
if (-1 == pThis->nVideoStreamIdx)
return E_FAIL;
pThis->pAVCodecContext = avcodec_alloc_context3(pAVCodec);
if (!pThis->pAVCodecContext)
return E_FAIL;
if (0 > avcodec_parameters_to_context(pThis->pAVCodecContext, pAVCodecParameters))
return E_FAIL;
if (0 > avcodec_open2(pThis->pAVCodecContext, pAVCodec, 0))
return E_FAIL;
pThis->pAVFrame = av_frame_alloc();
if (!pThis->pAVFrame)
return E_FAIL;
pThis->pAVFrameOut = av_frame_alloc();
if (!pThis->pAVFrameOut)
return E_FAIL;
else
{
pThis->pAVFrameOut->width = pThis->width;
pThis->pAVFrameOut->height = pThis->height;
pThis->pAVFrameOut->linesize[0] = pThis->width * 4;
}
pThis->pAVPacket = av_packet_alloc();
if (!pThis->pAVPacket)
return E_FAIL;
(*pFileOpen) = 1;
return S_OK;
}
HRESULT ID2DVideoDecoder_GetVideoInfo(ID2DVideoDecoder* pThis, D2DVideoInfo* pD2DVideoInfo)
{
pD2DVideoInfo->nWidth = pThis->width;
pD2DVideoInfo->nHeight = pThis->height;
pD2DVideoInfo->TimeBase = pThis->TimeBase;
return S_OK;
}
//UINT8* dst[4] = { pVideoFrame, 0, 0, 0 };
//int dst_linesize[4] = { pThis->width * 4, 0, 0, 0 };
HRESULT ID2DVideoDecoder_GetNextFrame(ID2DVideoDecoder* pThis, void* pVideoFrame)
{
av_assert0(pVideoFrame);
while (0 <= av_read_frame(pThis->pAVFormatContext, pThis->pAVPacket))
{
if (pThis->pAVPacket->stream_index == pThis->nVideoStreamIdx)
{
pThis->pts = pThis->pAVPacket->pts;
AVPixelFormat pix_fmt = EnsurePixelFormat(pThis->pAVCodecContext->pix_fmt);
const AVPixFmtDescriptor* desc = av_pix_fmt_desc_get(pix_fmt);
pThis->pSwsContext =
sws_getCachedContext(
pThis->pSwsContext,
pThis->width,
pThis->height,
pix_fmt,
pThis->width,
pThis->height,
AV_PIX_FMT_BGRA,
SWS_FAST_BILINEAR,
0,
0,
0
);
av_assert0(pThis->pSwsContext);
pThis->pAVFrameOut->data[0] = pVideoFrame;
CpuDecodeFrame(
pThis->pAVCodecContext,
pThis->pAVPacket,
pThis->pAVFrame,
pThis->pAVFrameOut,
pThis->pSwsContext
);
break;
}
}
if (pThis->pAVPacket->buf)
{
av_packet_unref(pThis->pAVPacket);
}
return S_OK;
}
HRESULT ID2DVideoDecoder_AdvanceFrame(ID2DVideoDecoder* pThis)
{
int ret;
ret = av_read_frame(pThis->pAVFormatContext, pThis->pAVPacket);
if (0 > ret)
{
if (AVERROR_EOF == ret)
{
return ERROR_HANDLE_EOF;
}
return E_FAIL;
}
//TODO: Callback Exec
av_packet_unref(pThis->pAVPacket);
return E_NOTIMPL;
}
void ID2DVideoDecoder_CloseVideo(ID2DVideoDecoder* pThis)
{
if (pThis->pAVCodecContext)
{
avcodec_free_context(&pThis->pAVCodecContext);
}
if (pThis->pAVFormatContext)
{
avformat_close_input(&pThis->pAVFormatContext);
}
if (pThis->pAVPacket)
{
av_packet_free(&pThis->pAVPacket);
}
if (pThis->pAVFrame)
{
av_frame_free(&pThis->pAVFrame);
}
if (pThis->pAVFrameOut)
{
av_frame_free(&pThis->pAVFrameOut);
}
if (pThis->pSwsContext)
{
sws_freeContext(pThis->pSwsContext);
}
memset(pThis, 0, sizeof(ID2DVideoDecoder));
return S_OK;
}
INT32 ID2DVideoDecoder_GetFrameWidth(const ID2DVideoDecoder* pThis)
{
av_assert0(pThis && pThis->pAVFormatContext && pThis->pAVCodecContext);
return pThis->pAVCodecContext->width;
}
INT32 ID2DVideoDecoder_GetFrameHeight(const ID2DVideoDecoder* pThis)
{
av_assert0(pThis && pThis->pAVFormatContext && pThis->pAVCodecContext);
return pThis->pAVCodecContext->height;
}
DOUBLE ID2DVideoDecoder_GetFramerate(const ID2DVideoDecoder* pThis)
{
av_assert0(pThis && pThis->pAVFormatContext && pThis->pAVCodecContext);
return av_q2d(pThis->pAVCodecContext->framerate);
}
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "libavutil/rational.h"
typedef double DOUBLE;
typedef struct D2DVideoDecoder ID2DVideoDecoder;
typedef struct D2DsVideoInfo
{
int nWidth;
int nHeight;
AVRational TimeBase;
} D2DVideoInfo;
HRESULT ID2DVideoDecoder_Create(ID2DVideoDecoder** pThis);
HRESULT ID2DVideoDecoder_OpenVideo(ID2DVideoDecoder* pThis, const char* file, INT32* pFileOpen);
HRESULT ID2DVideoDecoder_GetVideoInfo(ID2DVideoDecoder* pThis, D2DVideoInfo* pD2DVideoInfo);
HRESULT ID2DVideoDecoder_GetNextFrame(ID2DVideoDecoder* pThis, void* pVideoFrame);
HRESULT ID2DVideoDecoder_AdvanceFrame(ID2DVideoDecoder* pThis);
void ID2DVideoDecoder_CloseVideo(ID2DVideoDecoder* pThis);
INT32 ID2DVideoDecoder_GetFrameWidth(const ID2DVideoDecoder* pThis);
INT32 ID2DVideoDecoder_GetFrameHeight(const ID2DVideoDecoder* pThis);
DOUBLE ID2DVideoDecoder_GetFramerate(const ID2DVideoDecoder* pThis);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment