windows c语言简单在窗口ffmpeg播放mp4

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "swscale.lib")
#pragma comment(lib, "gdi32.lib")  // GDI 库

#define VIDEO_WIDTH 640
#define VIDEO_HEIGHT 480

// 渲染帧到窗口的函数(使用 GDI 绘制)
void RenderFrameToWindow(HWND hwnd, AVFrame *frame) {
    // 获取设备上下文
    HDC hdc = GetDC(hwnd);
    if (!hdc) {
        fprintf(stderr, "Failed to get device context\n");
        return;
    }

    // 创建一个兼容的内存 DC
    HDC memDC = CreateCompatibleDC(hdc);
    if (!memDC) {
        fprintf(stderr, "Failed to create memory DC\n");
        ReleaseDC(hwnd, hdc);
        return;
    }

    // 创建位图对象
    HBITMAP hBitmap = CreateCompatibleBitmap(hdc, VIDEO_WIDTH, VIDEO_HEIGHT);
    if (!hBitmap) {
        fprintf(stderr, "Failed to create bitmap\n");
        DeleteDC(memDC);
        ReleaseDC(hwnd, hdc);
        return;
    }

    // 将内存 DC 与位图关联
    HGDIOBJ oldBitmap = SelectObject(memDC, hBitmap);

    // 获取 RGB 数据
    uint8_t *rgb_data = (uint8_t *)malloc(VIDEO_WIDTH * VIDEO_HEIGHT * 3);
    uint8_t *dst_data[4] = {rgb_data, NULL, NULL, NULL};
    int dst_linesize[4] = {VIDEO_WIDTH * 3, 0, 0, 0};

    // 使用 sws_getContext 来确保转换正确
    struct SwsContext *sws_ctx = sws_getContext(frame->width, frame->height, frame->format,
                                                 VIDEO_WIDTH, VIDEO_HEIGHT, AV_PIX_FMT_RGB24,
                                                 SWS_BICUBIC, NULL, NULL, NULL);
    sws_scale(sws_ctx, frame->data, frame->linesize, 0, frame->height, dst_data, dst_linesize);

    // 反转图像上下
    for (int y = 0; y < VIDEO_HEIGHT / 2; y++) {
        for (int x = 0; x < VIDEO_WIDTH * 3; x++) {
            uint8_t temp = rgb_data[y * VIDEO_WIDTH * 3 + x];
            rgb_data[y * VIDEO_WIDTH * 3 + x] = rgb_data[(VIDEO_HEIGHT - 1 - y) * VIDEO_WIDTH * 3 + x];
            rgb_data[(VIDEO_HEIGHT - 1 - y) * VIDEO_WIDTH * 3 + x] = temp;
        }
    }

    // 创建 BITMAPINFO
    BITMAPINFOHEADER biHeader;
    biHeader.biSize = sizeof(BITMAPINFOHEADER);
    biHeader.biWidth = VIDEO_WIDTH;
    biHeader.biHeight = VIDEO_HEIGHT;
    biHeader.biPlanes = 1;
    biHeader.biBitCount = 24;  // RGB24
    biHeader.biCompression = BI_RGB;
    biHeader.biSizeImage = VIDEO_WIDTH * VIDEO_HEIGHT * 3;
    biHeader.biXPelsPerMeter = 0;
    biHeader.biYPelsPerMeter = 0;
    biHeader.biClrUsed = 0;
    biHeader.biClrImportant = 0;

    BITMAPINFO bmi = {0};
    bmi.bmiHeader = biHeader;

    // 使用 GDI 绘制位图
    SetDIBitsToDevice(hdc, 0, 0, VIDEO_WIDTH, VIDEO_HEIGHT, 0, 0, 0, VIDEO_HEIGHT,
                      rgb_data, &bmi, DIB_RGB_COLORS);

    // 清理
    free(rgb_data);
    SelectObject(memDC, oldBitmap);
    DeleteObject(hBitmap);
    DeleteDC(memDC);
    ReleaseDC(hwnd, hdc);
}


// 自定义窗口过程函数,用来处理窗口的消息
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <video_file>\n", argv[0]);
        return -1;
    }

    // 初始化 FFmpeg
    avformat_network_init();
    AVFormatContext *fmt_ctx = NULL;
    if (avformat_open_input(&fmt_ctx, argv[1], NULL, NULL) < 0) {
        fprintf(stderr, "Could not open input file\n");
        return -1;
    }

    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        fprintf(stderr, "Could not find stream information\n");
        return -1;
    }

    // 查找视频流
    int video_stream_index = -1;
    for (int i = 0; i < fmt_ctx->nb_streams; i++) {
        if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_stream_index = i;
            break;
        }
    }
    
    if (video_stream_index == -1) {
        fprintf(stderr, "Could not find video stream\n");
        return -1;
    }

    AVStream *video_stream = fmt_ctx->streams[video_stream_index];
    AVCodec *codec = avcodec_find_decoder(video_stream->codecpar->codec_id);
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        return -1;
    }
    
    AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
    if (avcodec_parameters_to_context(codec_ctx, video_stream->codecpar) < 0) {
        fprintf(stderr, "Could not copy codec parameters to context\n");
        return -1;
    }

    if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        return -1;
    }

    // 初始化窗口
    WNDCLASSA cls={0};
    cls.lpszClassName="main";
    cls.lpfnWndProc=WindowProc;
    RegisterClassA(&cls);
    HWND hwnd = CreateWindowA("main", "FFmpeg Video Player", WS_OVERLAPPEDWINDOW,
                              100, 100, VIDEO_WIDTH, VIDEO_HEIGHT, NULL, NULL, NULL, NULL);
    ShowWindow(hwnd, SW_SHOW);
    UpdateWindow(hwnd);

    // 解码和渲染部分
    AVPacket packet;
    AVFrame *frame = av_frame_alloc();
    MSG msg;
    while (av_read_frame(fmt_ctx, &packet) >= 0) {
        if (packet.stream_index == video_stream_index) {
            if (avcodec_send_packet(codec_ctx, &packet) < 0) {
                fprintf(stderr, "Error sending packet to codec\n");
                break;
            }

            while (avcodec_receive_frame(codec_ctx, frame) >= 0) {
                // 渲染帧到窗口
                RenderFrameToWindow(hwnd, frame);

                // 处理消息
                if (PeekMessageA(&msg, hwnd, 0, 0, PM_REMOVE)) {
                    TranslateMessage(&msg);
                    DispatchMessageA(&msg);
                }

                Sleep(30); // 为了控制视频播放的帧率
            }
        }

        av_packet_unref(&packet);
    }

    // 清理资源
    av_frame_free(&frame);
    avcodec_free_context(&codec_ctx);
    avformat_close_input(&fmt_ctx);

    return 0;
}

mingw编译命令为

bash 复制代码
gcc -o a.exe a.c -IYouIncludePath -LYouLibPath -l:avcodec.lib -l:avformat.lib -l:swscale.lib  -llibavutil -lgdi32 -luser32
相关推荐
祈安_3 天前
C语言内存函数
c语言·后端
埃博拉酱4 天前
VS Code Remote SSH 连接 Windows 服务器卡在"下载 VS Code 服务器":prcdn DNS 解析失败的诊断与 BITS 断点续传
windows·ssh·visual studio code
唐宋元明清21884 天前
.NET 本地Db数据库-技术方案选型
windows·c#
加号34 天前
windows系统下mysql多源数据库同步部署
数据库·windows·mysql
norlan_jame4 天前
C-PHY与D-PHY差异
c语言·开发语言
tryCbest4 天前
Windows环境下配置pip镜像源
windows·pip
呉師傅4 天前
火狐浏览器报错配置文件缺失如何解决#操作技巧#
运维·网络·windows·电脑
czy87874754 天前
除了结构体之外,C语言中还有哪些其他方式可以模拟C++的面向对象编程特性
c语言
百事牛科技4 天前
保护文档安全:PDF限制功能详解与实操
windows·pdf
一个人旅程~4 天前
如何用命令行把win10/win11设置为长期暂停更新?
linux·windows·经验分享·电脑