Last active
July 26, 2025 19:52
-
-
Save Stehfyn/96296a3c33033f852794f8a5bcbf3034 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| #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); | |
| } |
This file contains hidden or 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
| #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