惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
WordPress大学
WordPress大学
T
Tailwind CSS Blog
V
Visual Studio Blog
月光博客
月光博客
Hugging Face - Blog
Hugging Face - Blog
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - Franky
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
阮一峰的网络日志
阮一峰的网络日志
量子位
有赞技术团队
有赞技术团队
酷 壳 – CoolShell
酷 壳 – CoolShell
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
Jina AI
Jina AI
雷峰网
雷峰网
博客园 - 【当耐特】
博客园 - 叶小钗
美团技术团队
宝玉的分享
宝玉的分享
IT之家
IT之家

博客园 - 飘杨......

为ZLMediaKit在windows10编译srtp Windows10安装部署ZLMediaKit SurfaceView+EGL+OpenGL ES+ffmpeg播放视频并解决黑屏不显示画面的问题 SurfaceView+ANativeWindow+ffmpeg播放视频并解决花屏问题 SDL播放音频工具类封装 Qt QWidget中dropEvent(QDropEvent* e)拖拽放开不接收事件/不执行,且拖拽到目标后鼠标显示禁用符号 ffmpeg视频转码遇到H264黑屏问题 ffmpeg根据输入的参数截取视频 ffmpeg将视频流录制下来并保存到本地 ffmpeg解封装mp4并解码渲染(SDL2) Qt+ffmpeg+SDL硬件解码并渲染 FFmpeg实战:录制Windows屏幕并用FFmpeg压缩成H.264/H.265并保存 ffmpeg SwsContext像素格式转换BGRA转YUV420P H264/H265 NALU的nalu_unit_type解析 ffmpeg码率控制模式详解 ffmpeg-H264/H265常用编解码预设参数 Qt+FFmpeg+SDL 实现多路多格式原始视频播放工具:从像素处理到实时渲染 Qt+SDL 实战:多格式视频播放工具开发 —— 支持 RGBA/ARGB/RGB24/YUV420P 的完整实现 SDL将YUV视频渲染到Qt窗口播放
ffmpeg+sdl播放H264/H265文件
飘杨...... · 2025-05-22 · via 博客园 - 飘杨......

一、概述

  上一篇写了使用windows录屏+ffmpeg生成H264/H265数据,并存储成文件。本节就写下如何使用ffmpeg+sdl播放H264/H265裸数据文件。

  界面如下:

  1.播放前界面  

  

   2.播放后界面

  

二、代码示例

void H264OrH265FilePlayWindow::Draw()
{

    //找打解码器
    auto codec = avcodec_find_decoder((AVCodecID)codecId);
    if (!codec)
    {
        qDebug() << "无法找到解码器->avcodec_find_decoder";
        return;
    }
    //创建解码器上下文
    auto codecCtx = avcodec_alloc_context3(codec);
    if (!codecCtx)
    {
        qDebug() << "解码器山下文创建失败->avcodec_alloc_context3";
        return;
    }
    codecCtx->thread_count = 16;//16线程解码
    //打开解码器
    int ret = avcodec_open2(codecCtx, NULL, NULL);
    if (ret != 0)
    {
        qDebug() << "解码器打开失败->avcodec_open2";
        return;
    }

    //创建文件分割上下文
    auto parser = av_parser_init(codecId);
    //申请packet空间
    auto pkt = av_packet_alloc();
    //申请frame空间
    auto frame = av_frame_alloc();
    while (isRunning)
    {
        bool flag = reader->Read((char*)inbuf, sizeof(inbuf));
        if (!flag)
        {
            qDebug() << "文件读取结束";
            break;
        }
        int data_size = reader->getBytesCount();
        if (data_size <= 0) {
            qDebug() << "没有读到数据退出循环";
            break;
        }
        auto data = inbuf;
        while (data_size > 0) //一次有多帧数据
        {
            //通过0001 截断输出到AVPacket 返回帧大小
            int ret = av_parser_parse2(parser, codecCtx,
                &pkt->data, &pkt->size, //输出
                data, data_size,        //输入
                AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0
            );
            data += ret;
            data_size -= ret; //已处理
            if (pkt->size)
            {
                //cout << pkt->size << " "<<flush;
                //发送packet到解码线程
                ret = avcodec_send_packet(codecCtx, pkt);
                if (ret < 0)
                    break;
                //获取多帧解码数据
                while (ret >= 0)
                {
                    //每次回调用av_frame_unref 
                    ret = avcodec_receive_frame(codecCtx, frame);
                    if (ret < 0)
                        break;
                    qDebug() << frame->format << " ";
                    renderView->DrawFrame(frame);
                    std::this_thread::sleep_for(std::chrono::milliseconds(1000/25));
                }
            }
        }
        
    }
    ///取出缓存数据
    ret = avcodec_send_packet(codecCtx, NULL);
    while (ret >= 0)
    {
        ret = avcodec_receive_frame(codecCtx, frame);
        if (ret < 0)
            break;
        qDebug() << frame->format << "-";
    }

    av_parser_close(parser);
    avcodec_free_context(&codecCtx);
    av_frame_free(&frame);
    av_packet_free(&pkt);
}