ffmpeg学习(三)——ffmpeg+SDL2 实现简单播放器

本篇实现基于ffmpeg动态库用测试程序播放本地文件和RTSP视频流。

参考文章:http://blog.csdn.net/leixiaohua1020/article/details/8652605

http://blog.csdn.net/guanghua2_0beta/article/details/37578299

创建工程,参考上一篇文章:http://www.cnblogs.com/wenjingu/p/3990071.html,注意:下载SDL2库的开发版,lib文件放到lib文件夹下,dll放到debug文件夹下。

代码如下,在参考文章的基础上做了少量改动,主要是将ffmpeg老版本的部分函数在替换为2.4版本中的新函数。

#include "stdafx.h"

#ifdef __cplusplus
extern "C" {
#endif

#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
#include <SDL2/SDL.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#ifdef __cplusplus
}
#endif

int ffplayer()
{
    AVFormatContext    *pFormatCtx;
    int                i, videoindex;
    AVCodecContext    *pCodecCtx;
    AVCodec            *pCodec;
    //char filepath[]="F:\\Work\\ffmpegdemo\\Debug\\Wildlife.wmv";
    char rtspUrl[] = "rtsp://admin:[email protected]:554";
    av_register_all();//注册组件
    avformat_network_init();//支持网络流
    pFormatCtx = avformat_alloc_context();//初始化AVFormatContext
    if(avformat_open_input(&pFormatCtx,/*filepath*/rtspUrl,NULL,NULL)!=0){//打开文件或网络流
        printf("无法打开文件\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++) //获取视频流ID
        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;
    }
    AVFrame    *pFrame,*pFrameYUV;
    pFrame=avcodec_alloc_frame();//存储解码后AVFrame
    pFrameYUV=avcodec_alloc_frame();//存储转换后AVFrame
    uint8_t *out_buffer;
    out_buffer=new uint8_t[avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height)];//分配AVFrame所需内存
    avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);//填充AVFrame

    //------------SDL初始化--------
    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
        printf( "Could not initialize SDL - %s\n", SDL_GetError());
        return -1;
    }
    SDL_Window *screen = SDL_CreateWindow("RTSP Client Demo",
                          SDL_WINDOWPOS_UNDEFINED,
                          SDL_WINDOWPOS_UNDEFINED,
                          pCodecCtx->width, pCodecCtx->height,
                          SDL_WINDOW_RESIZABLE/* SDL_WINDOW_HIDDEN*/| SDL_WINDOW_OPENGL);
    if(!screen) {
        printf("SDL: could not set video mode - exiting\n");
        return -1;
    }
    SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0);
    SDL_Texture* sdlTexture = SDL_CreateTexture(
        sdlRenderer,
        SDL_PIXELFORMAT_YV12,
        SDL_TEXTUREACCESS_STREAMING,
        pCodecCtx->width,
        pCodecCtx->height); 

    SDL_Rect rect;
    //-----------------------------
    int ret, got_picture;
    static struct SwsContext *img_convert_ctx;
    int y_size = pCodecCtx->width * pCodecCtx->height;

    SDL_Event event;
    AVPacket *packet=(AVPacket *)malloc(sizeof(AVPacket));//存储解码前数据包AVPacket
    av_new_packet(packet, y_size);
    //输出一下信息-----------------------------
    printf("文件信息-----------------------------------------\n");
    //av_dump_format(pFormatCtx,0,filepath,0);
    printf("-------------------------------------------------\n");
    //------------------------------
    while(av_read_frame(pFormatCtx, packet)>=0)//循环获取压缩数据包AVPacket
    {
        if(packet->stream_index==videoindex)
        {
            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);//解码。输入为AVPacket,输出为AVFrame
            if(ret < 0)
            {
                printf("解码错误\n");
                return -1;
            }
            if(got_picture)
            {
                //像素格式转换。pFrame转换为pFrameYUV。
                img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
                sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
                sws_freeContext(img_convert_ctx);
                //------------SDL显示--------
                rect.x = 0;
                rect.y = 0;
                rect.w = pCodecCtx->width;
                rect.h = pCodecCtx->height;    

                SDL_UpdateTexture( sdlTexture, &rect, pFrameYUV->data[0], pFrameYUV->linesize[0] );
                SDL_RenderClear( sdlRenderer );
                SDL_RenderCopy( sdlRenderer, sdlTexture, &rect, &rect );
                SDL_RenderPresent( sdlRenderer );
                //延时20ms
                SDL_Delay(20);
                //------------SDL-----------
            }
        }
        av_free_packet(packet);
        SDL_PollEvent(&event);
        switch( event.type ) {
            case SDL_QUIT:
                SDL_Quit();
                exit(0);
                break;
            default:
                break;
        }
    }

    SDL_DestroyTexture(sdlTexture);
    delete[] out_buffer;
    av_free(pFrameYUV);
    avcodec_close(pCodecCtx);
    avformat_close_input(&pFormatCtx);

    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    ffplayer();

    return 0;
}

测试效果:

播放rtsp网络流

也可以播放本地文件,将rtspUrl替换为filepath即可。

时间: 2024-08-29 18:29:56

ffmpeg学习(三)——ffmpeg+SDL2 实现简单播放器的相关文章

可视化作业——简单播放器的更新

本次我对之前的简单播放器进行了功能上的更新,主要加入了两个功能 1.能够播放在线音乐 2.可以将音乐缓存到本地 1.在编辑第一个功能的时候,我借鉴了很多,包括微软文档(https://msdn.microsoft.com/en-us/library/windows/apps/mt187272.aspx),其他同学的博客等等.而我的第一个版本的代码是这样的 private void TxtFilePath_KeyUp(object sender, KeyRoutedEventArgs e) { i

FFmpeg入门,简单播放器

一个偶然的机缘,好像要做直播相关的项目 为了筹备,前期做一些只是储备,于是开始学习ffmpeg 这是学习的第一课 做一个简单的播放器,播放视频画面帧 思路是,将视频文件解码,得到帧,然后使用定时器,1秒显示24帧 1.创建win32工程,添加菜单项 “打开” 为了避免闪烁,MyRegisterClass中设置hbrBackground为null 2.在main函数中初始化ffmpeg库:av_register_all(); 3.响应菜单打开 1 void LoadVideoPlay(HWND h

基于 ffmpeg时时彩源码 php 的跨平台播放器实现

随着时时彩源码 php[大神源码论坛]dsluntan.com  [布丁源码论坛]budingbbs.com 企娥3393756370 游戏娱乐等直播业务的增长,在移动端观看直播的需求也日益迫切.但是移动端原生的播放器对各种直播流的支持却不是很好.Android 原生的 MediaPlayer 不支持 flv.hls 直播流,iOS 只支持标准的 HLS 流.本文介绍一种基于 ffplay 框架下的跨平台播放器的实现,且兼顾硬解码的实现. 播放器原理: 直观的讲,我们播放一个媒体文件一般需要5个

基于ffmpeg和libvlc的视频剪辑、播放器

以前研究的时候,写过一个简单的基于VLC的视频播放器.后来因为各种项目,有时为了方便测试,等各种原因,陆续加了一些功能,现在集成了视频播放.视频加减速.视频剪切,视频合并(增加中)等功能在一起.有时候看点网上下载的视频,可以一边看,一边能处理视频前后的广告,感觉也还可以用,就想把它开源出去,一方面希望有需要的朋友可以参考.借鉴,另一方面也希望可以促进它进一步的丰富功能,最终能实现一款简单又够用的视频剪辑软件. 程序框架 先上一张程序截图 基本上讲,它的播放功能是基于VLC,剪辑功能是基于FFmp

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

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

最简单的基于FFmpeg的内存读写的例子:内存播放器

打算记录两个最简单的FFmpeg进行内存读写的例子.之前的所有有关FFmpeg的例子都是对文件进行操作的.例如<100行代码实现最简单的基于FFMPEG+SDL的视频播放器>播放的是一个视频的文件.而<最简单的基于FFMPEG的转码程序>也是将一个视频文件转换为另一个视频文件.<最简单的基于FFmpeg的视频编码器(YUV编码为H.264)>也是最后编码得到一个H.264视频文件.实际上,并不是所有视频的编码,解码都是针对文件进行处理的.有的时候需要的解码的视频数据在一

(转)最简单的基于FFmpeg的内存读写的例子:内存播放器

ffmpeg内存播放解码 目录(?)[+] ===================================================== 最简单的基于FFmpeg的内存读写的例子系列文章列表: 最简单的基于FFmpeg的内存读写的例子:内存播放器 最简单的基于FFmpeg的内存读写的例子:内存转码器 ===================================================== 打算记录两个最简单的FFmpeg进行内存读写的例子.之前的所有有关FFmpe

html5标签video(播放器)学习笔记(一)-初始化的工作

最近有在学习html5中video标签(播放器)的使用,这里做一些学习笔记,方便自己查阅和记录,本文是第一篇,将介绍的是使用该标签初始化该做的哪些工作. 网上的教程其实也不少了 w3cschool里面的最为简单而详细,那么这几介绍的是一些更为直接的应用. 本文目录: 使用标签 加上一些必要参数 自动播放或自动加载 规范播放器 第一步:使用标签     使用的方法很简单,就是一句代码: <video></video> 第二步:加上一些必要的参数,比如播放视频的路径.是否显示控制条  

RemoteViews用法三:包含的widget的类音乐播放器

关于widget的用法参考:RemoteViews用法一:widget简单用法 RemoteViews用法二:可以接收点击事件并改变外观的widget 这篇博文主要是完成一个类音乐播放器,全面的应用activity,widget,service这几个类. 下载: 代码不算少,就不在这里粘代码了,先把源码下载地址奉上:http://download.csdn.net/detail/u011647962/8184423 demo效果: 为什么这个demo叫类音乐播放器呢,因为只有播放器的形,没有播放