最简单的基于ffmpeg+SDL的视频播放器

基于ffmpeg和SDL的音视频播放器 首先从队列中提取数据包到packet,并将提取的数据包出队列,然后调用avcodec_decode_video2解码packet得到一帧数据,然后av_frame_get_best_effort_timestamp得到当前帧的pts,调用synchronize_video更新视频帧的 PTS,然后调用queue_picture将解码成功的frame放进数据缓冲区。这个函数主要是做一些解码前的准备工作,然后打开解码器,并初始化(packet_queue_init)音频流队列和视频流队列(未解码前的)。 阅读详情
环境:

ubuntu 12.04
Qt 5.5.0
ffmpeg 3.0.1
SDL 2.1


流程图

该播放器解码的流程用图的方式可以表示称如下形式:
流程图1

SDL显示YUV图像的流程图:
流程图2


simplest_ffmpeg_player(标准版)代码:

/**
 * 最简单的基于FFmpeg的视频播放器
 * Simplest FFmpeg Player
 *
 * 雷霄骅 Lei Xiaohua
 * leixiaohua1020@126.com
 * 中国传媒大学/数字电视技术
 * Communication University of China / Digital TV Technology
 * http://blog.youkuaiyun.com/leixiaohua1020
 *
 * 本程序实现了视频文件的解码和显示(支持HEVC,H.264,MPEG2等)。
 * 是最简单的FFmpeg视频解码方面的教程。
 * 通过学习本例子可以了解FFmpeg的解码流程。
 * This software is a simplest video player based on FFmpeg.
 * Suitable for beginner of FFmpeg.
 */


#include <stdio.h>

#define __STDC_CONSTANT_MACROS

#ifdef _WIN32
//Windows
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "SDL/SDL.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <SDL/SDL.h>
#ifdef __cplusplus
};
#endif
#endif


//Full Screen
#define SHOW_FULLSCREEN 0
//Output YUV420P
#define OUTPUT_YUV420P 0


int main(int argc, char* argv[])
{
    //FFmpeg
    AVFormatContext *pFormatCtx;
    int             i, videoindex;
    AVCodecContext  *pCodecCtx;
    AVCodec         *pCodec;
    AVFrame *pFrame,*pFrameYUV;
    AVPacket *packet;
    struct SwsContext *img_convert_ctx;
    //SDL
    int screen_w,screen_h;
    SDL_Surface *screen;
    SDL_VideoInfo *vi;
    SDL_Overlay *bmp;
    SDL_Rect rect;

    FILE *fp_yuv;
    int ret, got_picture;
    char filepath[]="test.mkv";

    av_register_all();
    avformat_network_init();

    pFormatCtx = avformat_alloc_context();

    if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){
        printf("Couldn't open input stream.\n");
        return -1;
    }
    if(avformat_find_stream_info(pFormatCtx,NULL)<0){
        printf("Couldn't find stream information.\n");
        return -1;
    }
    videoindex=-1;
    for(i=0; i<pFormatCtx->nb_streams; i++)
        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){
            videoindex=i;
            break;
        }
    if(videoindex==-1){
        printf("Didn't find a video stream.\n");
        return -1;
    }
    pCodecCtx=pFormatCtx->streams[videoindex]->codec;
    pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
    if(pCodec==NULL){
        printf("Codec not found.\n");
        return -1;
    }
    if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){
        printf("Could not open codec.\n");
        return -1;
    }

    pFrame=av_frame_alloc();
    pFrameYUV=av_frame_alloc();
    //uint8_t *out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
    //avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
    //SDL----------------------------
    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
        printf( "Could not initialize SDL - %s\n", SDL_GetError());
        return -1;
    }



#if SHOW_FULLSCREEN
    vi = SDL_GetVideoInfo();
    screen_w = vi->current_w;
    screen_h = vi->current_h;
    screen = SDL_SetVideoMode(screen_w, screen_h, 0,SDL_FULLSCREEN);
#else
    screen_w = pCodecCtx->width;
    screen_h = pCodecCtx->height;
    screen = SDL_SetVideoMode(screen_w, screen_h, 0,0);
#endif

    if(!screen) {
        printf("SDL: could not set video mode - exiting:%s\n",SDL_GetError());
        return -1;
    }

    bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,SDL_YV12_OVERLAY, screen);

    rect.x = 0;
    rect.y = 0;
    rect.w = screen_w;
    rect.h = screen_h;
    //SDL End------------------------


    packet=(AVPacket *)av_malloc(sizeof(AVPacket));
    //Output Information-----------------------------
    printf("------------- File Information ------------------\n");
    av_dump_format(pFormatCtx,0,filepath,0);
    printf("-------------------------------------------------\n");

#if OUTPUT_YUV420P
    fp_yuv=fopen("output.yuv","wb+");
#endif

    SDL_WM_SetCaption("Simplest FFmpeg Player",NULL);

    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
    //------------------------------
    while(av_read_frame(pFormatCtx, packet)>=0){
        if(packet->stream_index==videoindex){
            //Decode
            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
            if(ret < 0){
                printf("Decode Error.\n");
                return -1;
            }
            if(got_picture){
                SDL_LockYUVOverlay(bmp);
                pFrameYUV->data[0]=bmp->pixels[0];
                pFrameYUV->data[1]=bmp->pixels[2];
                pFrameYUV->data[2]=bmp->pixels[1];
                pFrameYUV->linesize[0]=bmp->pitches[0];
                pFrameYUV->linesize[1]=bmp->pitches[2];
                pFrameYUV->linesize[2]=bmp->pitches[1];
                sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0,
                    pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
#if OUTPUT_YUV420P
                int y_size=pCodecCtx->width*pCodecCtx->height;
                fwrite(pFrameYUV->data[0],1,y_size,fp_yuv);    //Y
                fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv);  //U
                fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv);  //V
#endif

                SDL_UnlockYUVOverlay(bmp);

                SDL_DisplayYUVOverlay(bmp, &rect);
                //Delay 40ms
                SDL_Delay(40);
            }
        }
        av_free_packet(packet);
    }

    //FIX: Flush Frames remained in Codec
    while (1) {
        ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
        if (ret < 0)
            break;
        if (!got_picture)
            break;
        sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);

        SDL_LockYUVOverlay(bmp);
        pFrameYUV->data[0]=bmp->pixels[0];
        pFrameYUV->data[1]=bmp->pixels[2];
        pFrameYUV->data[2]=bmp->pixels[1];
        pFrameYUV->linesize[0]=bmp->pitches[0];
        pFrameYUV->linesize[1]=bmp->pitches[2];
        pFrameYUV->linesize[2]=bmp->pitches[1];
#if OUTPUT_YUV420P
        int y_size=pCodecCtx->width*pCodecCtx->height;
        fwrite(pFrameYUV->data[0],1,y_size,fp_yuv);    //Y
        fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv);  //U
        fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv);  //V
#endif

        SDL_UnlockYUVOverlay(bmp);
        SDL_DisplayYUVOverlay(bmp, &rect);
        //Delay 40ms
        SDL_Delay(40);
    }

    sws_freeContext(img_convert_ctx);

#if OUTPUT_YUV420P
    fclose(fp_yuv);
#endif

    SDL_Quit();

    //av_free(out_buffer);
    av_free(pFrameYUV);
    avcodec_close(pCodecCtx);
    avformat_close_input(&pFormatCtx);

    return 0;
}

.pro文件如下:

TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += main.cpp

include(deployment.pri)
qtcAddDeployment()

LIBS += -lSDL \
        -lavcodec \
        -lavdevice \
        -lavfilter \
        -lavformat \
        -lswresample \
        -lavutil \
        -lswscale

编译运行即可。


运行结果

运行结果如下:
结果1
结果2
ps:本文转载自雷霄骅大神的博客(http://blog.youkuaiyun.com/leixiaohua1020)的博文,由于使用的平台不同和ffmpeg版本不同,故稍加修改。


本文出处:

http://blog.youkuaiyun.com/leixiaohua1020/article/details/8652605

最简单的基于FFMPEG+SDL的视频播放器 ver2(采用SDL2.0) 流程图 FFmpeg解码一个视频流程如下图所示: SDL2.0显示YUV的流程图: 对比SDL1.2的流程图,发现变化还是很大的。几乎所有的API都发生了变化。但是函数和变量有一定的对应关系: SDL_SetVideoMode()————SDL_CreateWindow() SDL_Surface————SDL_Window SDL_CreateYUVOverlay()————SDL_CreateTexture() SDL_Overlay————SDL_Texture 不再一一例举。 阅读详情

相关推荐

弹簧管压力表设计报告

精密机械课程设计 弹簧管压力表设计报告 2020年5月1日 目 录 第一章 设计任务概述... 3 1.1 课程设计目的... 3 1.2 设计任务... 3 1.3 技术指标... 3 第二章 压力表概述... 4 2.1 机械式压力表的组成部分... 4 2.2 工作原理... 4 第三章 压力表设计... 5 3.1 弹簧管参数设计... 5 3.2 曲柄滑块机构设计... ...

weixin_42163746的博客 6448

【项目教程】FFmpeg+SDL2实现视频播放器

【项目教程】FFmpeg+SDL2实现视频播放器

m0_73443478的博客 2190

NLP实战:如何用CoNLL-2003数据集快速提升命名实体识别模型性能(附完整代码)

本文详细介绍了如何利用CoNLL-2003公开数据集,通过深度剖析数据特点、构建鲁棒的数据预处理流水线、选择合适的模型架构(如BERT-CRF)以及优化训练策略,来系统性地提升命名实体识别(NER)模型的性能。文章提供了完整的代码示例,并分享了处理数据不均衡、标签对齐等核心挑战的实战技巧,帮助读者从理论到实践全面掌握NER任务。

cola5的博客 494

PPSSPP UI框架:跨平台界面设计和主题系统

作为一款跨平台的PSP模拟器,PPSSPP不仅在游戏兼容性上表现卓越,其UI框架也为开发者提供了灵活强大的界面设计和主题定制能力。本文将深入剖析PPSSPP的UI架构设计、主题系统实现以及跨平台适配策略,帮助开发者快速掌握界面定制技巧,打造个性化模拟器体验。 读完本文你将获得: - 理解PPSSPP UI框架的核心架构与组件设计 - 掌握主题系统的工作原理及自定义方法 - 了解跨平台界面适配的实...

gitblog_01095的博客 525

Python 包安装报错:ERROR: No matching distribution found for xxx 的全面排查指南

本文全面解析Python包安装时常见的`ERROR: No matching distribution found for xxx`报错。从检查包名拼写、网络与镜像源配置,到深入分析Python版本、操作系统等环境兼容性问题,提供了从简到繁的排查步骤。文章还介绍了使用`pip debug`、`-v`参数等高级诊断工具,并给出了更换包管理器、使用Docker等终极解决方案,帮助开发者高效解决依赖安装难题。

p8q9r0的博客 894

SAP 公司间库存调拨通过IDOC完成自动发票校验

本文仅用于SAP软件的应用与学习,不代表SAP公司。(注:文中所示截图来源SAP ERP软件,软件相应著作权归SAP所有。公司间采购时,通过SAP内部EDI 数据传输功能, 由销售方开的公司间发票自动触发采购方的发票校验。​欢迎扫码加如下微信,我会把大家拉到SAP PP学习群,随时欢迎跟我和其他SAP PP顾问一起交流和学习,如下图库存调拨订单,系统已经完成了发货方发货和收货方收货。

2402_84262664的博客 923

基于SDL的yuv视频播放

YUV的播放涉及到创建窗口和创建线程,在窗口中传入YUV码流数据,以达到播放视频的目的。窗口拉伸时,相应的长宽数据也会打印在命令框上。## 1 基于SDL的yuv视频播放。显示窗口的长宽比例可自己设置。

weixin_69942267的博客 775

SAP CRP能力计划详细说明操作及相关配置

2、求助朋友同事的希望破灭后,网上找了资料发现在百度搜索的资料基本都是没有说明白什么才产能计划,都没有详细的操作说明,然后用google去搜索了一些相关的文章,好像也没有详细的文章。然后也去SAP的官网搜索了相关的文章,都是文字性的表述,对系统的配置都没有很大的帮助,很久之前有记得在隐身人的博客中有提到CRP的能力计划的文章,然后试着去找了一下相关的文章。5、首先产能排产肯定涉及的就是是能力的问题,能力第一个能想到的就是工作中心中的能力页签,在流程制造中也叫资源,其实都是一个东西。

我小时候很黑的博客 4516

ffmpeg+SDL2实现播放器(二)

在上一篇文章中,代码的画面刷新不是定期实现的,这就导致视频的播放速度与实际不符,因此我们需要对其进行修改,使用多线程实现画面刷新的控制。 该工程使用的ffmpeg版本为5.01,SDL版本为2.0.22。 #include<iostream> #include<string.h> #include<SDL.h> extern "C" { #include "libavformat/avformat.h" //头文件不仅要在项目中鼠标点击配置,在代码中也要引入 #in

师范大学生的博客 908

【WRF-Urban】使用 LCZ 替换 WRF 运行中的 LUCC 数据

使用 LCZ 替换 WRF 运行中的 LUCC 数据

WW、forever的博客 987

【MATLAB-app】系列教程(含视频)第4、5、6课:实战_制作简单的图像处理软件

写作时间: 2020-12-27 我的教程目录 第1课:初步了解appdesigner 第2课:学会制作一个计算器 第3课:学习更多的控件(重点!) 第4课:实例1:制作一个图像处理软件 第5课:学习APPdesigner的设计精髓,框架 第6课:结合使用多种控件,函数等,丰富我们的实例1 第7课:app设计打包,完成工程应用导出 标题: 第4课:我的实例_学会制作一个图像处理软件 本文目录: 1.先看看我之前的一个工程 2.常用的基本组件控件 3.最常用且实用的控件的用法 -3.1 editfilel

wind 4051

100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)

FFMPEG工程浩大,可以参考的书籍又不是很多,因此很多刚学习FFMPEG的人常常感觉到无从下手。我刚接触FFMPEG的时候也感觉不知从何学起。 因此我把自己做项目过程中实现的一个非常简单的视频播放器(大约100行代码)源代码传上来,以作备忘,同时方便新手学习FFMPEG。 该播放器虽然简单,但是几乎包含了使用FFMPEG播放一个视频所有必备的API,并且使用SDL显示解码出来的视频。 并且

雷霄骅(leixiaohua1020)的专栏 24万+

华为OD机考双机位A卷 - 开心消消乐(Java & Python& JS & C/C++ & GO )

华为OD机考双机位A卷 - 开心消消乐(OD上机考试双机位A卷)。提供在线OJ刷题。Java、C++、Python、GO语言、C语言、JavaScript题解,并提供完整思路讲解。

算法大师! 1266

最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)

之前做过一个FFMPEG+SDL的简单播放器:《100行代码实现最简单的基于FFMPEG+SDL的视频播放器》。最近有不少人反映SDL已经升级到2.0版本了,甚至官网的Wiki上都只有SDL2.0的文档了,因此下载了SDL 2.0 并且进行了简单的研究。随后对此前的播放器进行了修改,将SDL1.2换成了SDL2.0。 注:《100行代码实现最简单的基于FFMPEG+SDL的视频播放器》文章中提到的很多知识这里不再重复。本文重点记录SDL1.2与SDL2.0的不同。

雷霄骅(leixiaohua1020)的专栏 14万+

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

100行代码实现最简单的基于FFMPEG+SDL的视频播放器

简介 FFMPEG工程浩大,可以参考的书籍又不是很多,因此很多刚学习FFMPEG的人常常感觉到无从下手。我刚接触FFMPEG的时候也感觉不知从何学起。 因此我把自己做项目过程中实现的一个非常简单的视频播放器(大约100行代码)源代码传上来,以作备忘,同时方便新手学习FFMPEG。 该播放器虽然简单,但是几乎包含了使用FFMPEG播放一个视频所有必备的API,并且使用SDL显示解码出来的视频...

雷霄骅(leixiaohua1020)的专栏 1万+

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

最简单的基于FFMPEG+SDL的视频播放器:拆分-解码器和播放器

本文补充记录《最简单的基于FFMPEG+SDL的视频播放器》中的两个例子:FFmpeg视频解码器和SDL像素数据播放器。这两个部分是从视频播放器中拆分出来的两个例子。FFmpeg视频解码器实现了视频数据到YUV数据的解码,而SDL像素数据播放器实现了YUV数据的显示。简而言之,原先的FFmpeg+SDL视频播放器实现了:视频数据->YUV->显示器FFmpeg视频解码器实现了:视频数据->YUVS

雷霄骅(leixiaohua1020)的专栏 3万+

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

最简单的基于FFMPEG+SDL的视频播放器

以上是完整的代码流程,包括初始化、解码、显示以及收尾工作。

m0_51386664的博客 173

最简单的基于FFMPEG+SDL的视频播放器-最终版

最简单的基于FFMPEG+SDL的视频播放器-最终版 去发现同类优质开源项目:https://gitcode.com/ 本项目提供了一个最简单的基于FFmpeg和SDL的视频播放器实现,支持多种视频格式的解码和显示,包括HEVC、H.264、MPEG2等。通过学习本例子,您可以了解FFmpeg的基本解码流程,并掌握如何使用SDL进行视频显示。 项目描述 本程序实现了视频文件的解码和显示功能,是最简...

gitblog_09751的博客 548

最简单的基于FFMPEG+SDL的视频播放器(新版ffmpeg接口)

博客原文地址 https://blog.youkuaiyun.com/leixiaohua1020/article/details/38868499 //因旧的ffmpeg部分函数已弃用,修改后的版本 //运行环境vs2015 +sdl 2+ffmpeg20200426 //代码的注释某位网友的,博主很懒就不找了 /** * 最简单的基于FFmpeg的视频播放器2(SDL升级版) * Simp...

tnb1992的博客 681

关于《最简单的基于FFMPEG+SDL的视频播放器》记录二

一、概述        之前写过一篇关于《最简单的基于FFMPEG+SDL的视频播放器》的记录,主要对FFMPEG的解码流程及代码做了比较详细的解释,但是对SDL部分并未做任何的解释,这次记录二将重点放在了SDL部分。由于SDL已经升级到2.0,所以此次将1.x和2.0一起记录下来。 二、SDL工作流程 SDL 1.x    1.流程图 这里直接借鉴作者的原图,处理流程图

GAMELOFT9----纸上得来终觉浅,绝知此事要躬行 1639

最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.youkuaiyun.com/jiangjunshow也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ===========

hffgjh的博客 294

最简单的基于FFMPEG+SDL的视频播放器 2.4

最简单的基于FFMPEG+SDL的视频播放器 2.4 去发现同类优质开源项目:https://gitcode.com/ 简介 本仓库提供了三个基于FFMPEG+SDL的视频播放器示例程序,用于帮助开发者理解和学习FFmpeg在视频解码方面的应用。这些示例程序支持多种视频编码格式,包括HEVC、H.264、MPEG2等,是最基础的FFmpeg视频解码教程。 示例程序 simplest_ffmpe...

gitblog_06738的博客 706

关于《最简单的基于FFMPEG+SDL的视频播放器》记录

一、概述         熟悉了FFMPEG的命令行工具ffmpeg.exe之后,就开始了对这个库的函数的熟悉过程,按照零基础学习FFMPEG的学习轨迹,就应当实现一个“最简单的视频播放器”来熟悉FFMPEG的工作流程和一些常用的函数。实现播放器的文章请参考最简单的视频播放器,这里仅仅记录一下自己的心得。 二、播放器的解码流程 播放器的解码流程非常重要,有利于我们去读懂代码。流程图我就不自己

GAMELOFT9----纸上得来终觉浅,绝知此事要躬行 1596
上一篇: ubuntu下SDL安装
下一篇: git学习笔记~checkout和reset
es716
博客等级 码龄14年 1粉丝 7原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值