Skip to content

Instantly share code, notes, and snippets.

@habibg1232191
Created February 1, 2023 14:04
Show Gist options
  • Save habibg1232191/6a235196f742b55b700933f59b7779d4 to your computer and use it in GitHub Desktop.
Save habibg1232191/6a235196f742b55b700933f59b7779d4 to your computer and use it in GitHub Desktop.
#include <windows.h> /* This enables access to Microsoft Windows specific data types that are required to use the Graphical User Interface of Windows. (HWND, WNDCLASSEX, etc.) */
#include <tchar.h> /* _T */
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include "skia/core/SkBitmap.h"
#include "skia/core/SkCanvas.h"
#include "skia/core/SkSurface.h"
#include "skia/core/SkPaint.h"
#include "skia/core/SkFont.h"
#include "skia/core/SkTextBlob.h"
#include "skia/core/SkImageEncoder.h"
#include "skia/core/SkStream.h"
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/samplefmt.h>
#include <libavutil/timestamp.h>
#include <libswscale/swscale.h>
}
int ret = 0;
AVFormatContext *pFormatCtx = NULL;
int videoStreamIndex = -1;
AVCodecContext *pCodecCtx = NULL;
AVCodec *pCodec = NULL;
AVFrame *pFrame = NULL;
AVPacket packet;
int frameFinished;
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
HWND hwnd;
void Draw(SkCanvas* canvas, int w, int h);
int init_ffmpeg()
{
av_register_all();
// Open video file
if (avformat_open_input(&pFormatCtx, "C:\\Users\\habib\\Videos\\Captures\\July 2022-08-13 13-06-51.mp4", NULL, NULL) != 0)
return -1; // Couldn't open file
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
return -1; // Couldn't find stream information
// Find the first video stream
for (int i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
break;
}
}
if (videoStreamIndex == -1)
return -1; // Didn't find a video stream
// Get a pointer to the codec context for the video stream
pCodecCtx = pFormatCtx->streams[videoStreamIndex]->codec;
// Find the decoder for the video stream
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL) {
fprintf(stderr, "Unsupported codec!\n");
return -1; // Codec not found
}
// Open codec
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
return -1; // Could not open codec
// Allocate video frame
pFrame = av_frame_alloc();
return 0;
}
int main(int argc, char* argv[]) {
if(init_ffmpeg() > 0)
return -1;
WNDCLASS wc;
const auto h_instance = GetModuleHandle(nullptr);
wc.style = 0;
wc.lpfnWndProc = reinterpret_cast<WNDPROC>(WndProc);
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = h_instance;
wc.hIcon = LoadIcon(nullptr,
IDI_APPLICATION);
wc.hCursor = LoadCursor(nullptr,
IDC_ARROW);
wc.hbrBackground = CreateSolidBrush(0xff000000);
wc.lpszMenuName = reinterpret_cast<LPCSTR>(L"MainMenu");
wc.lpszClassName = reinterpret_cast<LPCSTR>(L"MainWndClass");
wc.style = CS_VREDRAW | CS_HREDRAW;
if (!RegisterClass(&wc))
return FALSE;
hwnd = CreateWindowA(reinterpret_cast<LPCSTR>(L"MainWndClass"), "July",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, nullptr,
nullptr, h_instance, nullptr);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
BOOL bRet;
MSG msg;
while ((bRet = GetMessage(&msg, hwnd, 0, 0)) != 0) {
if (bRet == -1) {
// handle the error and possibly exit
}
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
void AVFrameToSkBitmap(AVFrame *frame, int width, int height, SkBitmap *pBitmap)
{
pBitmap->allocN32Pixels(width, height);
struct SwsContext *pSwsCtx = sws_getContext(width, height, AV_PIX_FMT_YUV420P,
width, height, AV_PIX_FMT_RGBA,
SWS_BILINEAR, nullptr, nullptr, nullptr);
uint8_t *dstData[1] = { (uint8_t*)pBitmap->getAddr(0, 0) };
int dstLinesize[1] = { 4 * width };
if(dstData[0] == nullptr || dstLinesize[0] == 0) return;
sws_scale(pSwsCtx, frame->data, frame->linesize, 0, height, dstData, dstLinesize);
// Free the scaling context
sws_freeContext(pSwsCtx);
}
int image_cout = 0;
void Draw(SkCanvas* canvas, int w, int h) {
SkPaint paint1, paint2, paint3;
paint1.setAntiAlias(true);
paint1.setColor(SK_ColorBLACK);
int fps = 60;
int frame_duration_ms = 1000 / fps;
auto start_time = std::chrono::high_resolution_clock::now();
if(av_read_frame(pFormatCtx, &packet) == 0)
{
if (packet.stream_index == videoStreamIndex) {
int result = avcodec_send_packet(pCodecCtx, &packet);
if (result < 0) {
std::cout << "avcodec_send_packet failed" << std::endl;
}
AVFrame* pFrame = av_frame_alloc();
if(avcodec_receive_frame(pCodecCtx, pFrame) > 0) return;
SkBitmap bitmap;
AVFrameToSkBitmap(pFrame, pFrame->width, pFrame->height, &bitmap);
auto image = SkImage::MakeFromBitmap(bitmap);
canvas->drawImage(image, 0, 0);
av_packet_alloc();
auto end_time = std::chrono::high_resolution_clock::now();
auto elapsed_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
if (elapsed_time_ms < frame_duration_ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(frame_duration_ms - elapsed_time_ms));
}
start_time = std::chrono::high_resolution_clock::now();
}
}
av_frame_free(&pFrame);
RECT size;
GetClientRect(hwnd, &size);
canvas->flush();
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT rt;
GetClientRect(hWnd, &rt);
int bmpw = rt.right - rt.left;
int bmph = rt.bottom - rt.top;
const size_t bmpSize = sizeof(BITMAPINFOHEADER) + bmpw * bmph * sizeof(uint32_t);
BITMAPINFO* bmpInfo = (BITMAPINFO*)new BYTE[bmpSize]();
bmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo->bmiHeader.biWidth = bmpw;
bmpInfo->bmiHeader.biHeight = -bmph;
bmpInfo->bmiHeader.biPlanes = 1;
bmpInfo->bmiHeader.biBitCount = 32;//Image 32 bits per pixel
bmpInfo->bmiHeader.biCompression = BI_RGB;
void* pixels = bmpInfo->bmiColors;//Picture pixel position pointer
SkImageInfo info = SkImageInfo::Make(bmpw, bmph,
kBGRA_8888_SkColorType, kPremul_SkAlphaType);
sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(info, pixels, bmpw * sizeof(uint32_t));
SkCanvas* canvas = surface->getCanvas();
canvas->clear(SK_ColorWHITE);//fill the white background
Draw(canvas, bmpw, bmph);//Call the function here and pass in the pointer drawing.
StretchDIBits(hdc, 0, 0, bmpw, bmph,
0, 0, bmpw, bmph,
pixels, bmpInfo,
DIB_RGB_COLORS, SRCCOPY);
delete[] bmpInfo;
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
av_free(pFrame);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
exit(0);
default:
goto label_msg_end;
}
return 0;
label_msg_end:
return DefWindowProc(hWnd, message, wParam, lParam);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment