演示基于SDL2.0+FFmpeg的播放器

SDL是一个跨平台的渲染组件,目前已经推出到2.0.3版本,支持Win/Linux/OSX/Android。网上很多介绍大多是基于SDL1.2版本的,与2.0版本有一定的差别,本文演示如何用SDL2.0版本播放视频(仅视频)。

SDL下载网站:http://libsdl.org

参考网址:http://blog.csdn.net/dawdo222/article/details/8692834

上代码:

// 演示如何用SDL2进行播放
//可参考http://blog.csdn.net/dawdo222/article/details/8692834

#include "stdafx.h"
#include <stdio.h>
#include <tchar.h>
#include <io.h>
#include <direct.h>
#include <windows.h>

extern "C"
{
    // ffmpeg
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
    // SDL
#include "SDL203include/SDL.h"
#include "SDL203include/SDL_thread.h"
};  

#pragma comment(lib,"../lib/avutil.lib")
#pragma comment(lib,"../lib/avcodec.lib")
#pragma comment(lib,"../lib/avformat.lib")
#pragma comment(lib,"../lib/swscale.lib")
#pragma comment(lib,"../lib/sdl2.lib")  

//把参数转换为utf8
void prepare_app_arguments2(int *argc_ptr, char ***argv_ptr)
{
	int i, nSize, newSize, buffsize;
	char *argv;
	char **argv2;
	wchar_t* lpWideCharStr;
	char* buf;
	char** win32_argv_utf8 = NULL;
	argv2 = *argv_ptr;

	buffsize = 0;
	/* determine the UTF-8 buffer size (including NULL-termination symbols) */
    for (i = 0; i < *argc_ptr; i++)
	{
		argv = argv2[i];
		nSize = MultiByteToWideChar(CP_ACP, 0, argv, strlen(argv)*sizeof(char), NULL, 0);
		lpWideCharStr = (wchar_t*)av_mallocz( (nSize+1) * sizeof(wchar_t));
		MultiByteToWideChar(CP_ACP, 0, argv, strlen(argv)*sizeof(wchar_t), lpWideCharStr, nSize);
        buffsize += WideCharToMultiByte(CP_UTF8, 0, lpWideCharStr, -1, NULL, 0, NULL, NULL);
		av_free(lpWideCharStr);
	}

    win32_argv_utf8 = (char**)av_mallocz(sizeof(char *) * (*argc_ptr + 1) + buffsize);

	for (i = 0; i < *argc_ptr; i++)
	{
		argv = argv2[i];
		nSize = MultiByteToWideChar(CP_ACP, 0, argv, strlen(argv)*sizeof(char), NULL, 0);
		lpWideCharStr = (wchar_t*)av_mallocz( (nSize+1) * sizeof(wchar_t));
		memset(lpWideCharStr, 0, (nSize+1)*sizeof(wchar_t));
		nSize = MultiByteToWideChar(CP_ACP, 0, argv, strlen(argv)*sizeof(wchar_t), lpWideCharStr, nSize);
		nSize =WideCharToMultiByte(CP_UTF8 ,0,lpWideCharStr,-1,NULL,0,NULL,NULL);
		buf = (char*)av_mallocz( (nSize+1) * sizeof(char));//new char[nSize+1];
		memset(buf, 0, nSize+1);
		newSize = WideCharToMultiByte(CP_UTF8 ,0,lpWideCharStr,-1,buf,nSize,NULL,NULL);
		av_free(lpWideCharStr);
		win32_argv_utf8[i] = buf;
	}
	*argc_ptr = *argc_ptr;
    *argv_ptr = win32_argv_utf8;
}

int _tmain(int argc, char* argv[])
{
	///////////////////////////////////////////////////////////////////////////////
    // ffmpeg
    // Register all formats and codecs
    av_register_all();  

    // Open video file
    AVFormatContext *pFormatCtx = NULL;
	prepare_app_arguments2(&argc, &argv);//转成UTF-8
    const char* filename = "d:\\clip\\avander2.mp4";//argv[1];
    if( avformat_open_input(&pFormatCtx, filename, 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
    }  

    // Dump information about file onto standard error
    av_dump_format(pFormatCtx, 0, filename, 0);
    // Find the first video stream
    int videoStream = -1;
    for(int i=0; i < pFormatCtx->nb_streams; i++) {
        if( pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) {
            videoStream = i;
            break;
        }
    }
    if( videoStream == -1) {
        return -1; // Didn‘t find a video stream
    }  

    // Get a pointer to the codec context for the video stream
    AVCodecContext * pCodecCtx = pFormatCtx->streams[videoStream]->codec;  

    // Find the decoder for the video stream
    AVCodec* pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if( pCodec == NULL ) {
        fprintf(stderr, "Unsupported codec!\n");
        return -1; // Codec not found
    }  

    // Open codec
    AVDictionary* optionsDict = NULL;
    if( avcodec_open2(pCodecCtx, pCodec, &optionsDict) < 0 ) {
        return -1; // Could not open codec
    }
	//源颜色格式
	AVPixelFormat src_fix_fmt = pCodecCtx->pix_fmt;	//AV_PIX_FMT_YUV420P
 	//目标颜色格式
	AVPixelFormat dst_fix_fmt = PIX_FMT_BGR24;//PIX_FMT_YUV420P
   // Allocate video frame
    AVFrame* pFrame = av_frame_alloc();
    AVFrame* pFrameYUV = av_frame_alloc();
    if( pFrameYUV == NULL ) {
        return -1;
    }  

    struct SwsContext* sws_ctx = sws_getContext(
        pCodecCtx->width,
        pCodecCtx->height,
        pCodecCtx->pix_fmt,
        pCodecCtx->width,
        pCodecCtx->height,
        dst_fix_fmt,//PIX_FMT_BGR24,//PIX_FMT_YUV420P,
        SWS_BILINEAR,
        NULL,
        NULL,
        NULL);  

    int numBytes = avpicture_get_size(
        dst_fix_fmt,//PIX_FMT_YUV420P,
        pCodecCtx->width,
        pCodecCtx->height);
    uint8_t* buffer = (uint8_t *)av_malloc( numBytes*sizeof(uint8_t) );  

    avpicture_fill((AVPicture *)pFrameYUV, buffer, dst_fix_fmt,//PIX_FMT_YUV420P,
        pCodecCtx->width, pCodecCtx->height);  

    // Read frames and save first five frames to disk
    SDL_Rect sdlRect;
    sdlRect.x = 0;
    sdlRect.y = 0;
    sdlRect.w = pCodecCtx->width;
    sdlRect.h = pCodecCtx->height;  

    //////////////////////////////////////////////////////
    // SDL
    if( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER )) {
        fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
        exit(1);
    }  

    SDL_Window* sdlWindow = SDL_CreateWindow("My Game Window",
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        pCodecCtx->width,  pCodecCtx->height,
        0);
    if( !sdlWindow ) {
        fprintf(stderr, "SDL: could not set video mode - exiting\n");
        exit(1);
    }  

    SDL_Renderer* sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_TARGETTEXTURE);  //原本第三个参数是0
    SDL_Texture* sdlTexture = SDL_CreateTexture(
        sdlRenderer,
        SDL_PIXELFORMAT_BGR24,//SDL_PIXELFORMAT_YV12,
        SDL_TEXTUREACCESS_STATIC,//SDL_TEXTUREACCESS_STREAMING,
        pCodecCtx->width,
        pCodecCtx->height);
	if(!sdlTexture)
		return -1;
	SDL_SetTextureBlendMode(sdlTexture,SDL_BLENDMODE_BLEND );

    AVPacket packet;
    SDL_Event event;
    while( av_read_frame(pFormatCtx, &packet) >= 0 ) {
        // Is this a packet from the video stream?
        if( packet.stream_index == videoStream ) {
            // Decode video frame
            int frameFinished;
            avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);  

            // Did we get a video frame?
            if( frameFinished ) {
                sws_scale(
                    sws_ctx,
                    (uint8_t const * const *)pFrame->data,
                    pFrame->linesize,
                    0,
                    pCodecCtx->height,
                    pFrameYUV->data,
                    pFrameYUV->linesize
                    );  

                SDL_UpdateTexture( sdlTexture, &sdlRect, pFrameYUV->data[0], pFrameYUV->linesize[0] );
                SDL_RenderClear( sdlRenderer );
                SDL_RenderCopy( sdlRenderer, sdlTexture, &sdlRect, &sdlRect );
                SDL_RenderPresent( sdlRenderer );
            }
            SDL_Delay(50);
        }  

        // Free the packet that was allocated by av_read_frame
        av_free_packet(&packet);
        SDL_PollEvent(&event);
        switch( event.type ) {
            case SDL_QUIT:
                SDL_Quit();
                exit(0);
                break;
            default:
                break;
        }  

    }  

    SDL_DestroyTexture(sdlTexture);  

    // Free the YUV frame
    av_free(pFrame);
    av_free(pFrameYUV);  

    // Close the codec
    avcodec_close(pCodecCtx);  

    // Close the video file
    avformat_close_input(&pFormatCtx);  

    return 0;
}

上述代码演示了如何把视频帧转换为BGR24格式,然后用SDL的纹理函数渲染到屏幕上。

不完善的地方:没有音频部分,更没有视音频同步,播放帧率固定设为20帧/秒。

演示基于SDL2.0+FFmpeg的播放器

时间: 2024-10-28 00:07:39

演示基于SDL2.0+FFmpeg的播放器的相关文章

基于Vue2.0的音乐播放器——歌手模块(拿不到数据)

来这里的都可能在看,慕课网vue2.0 的音乐播放器的相关页面,如果使用视频介绍的方法,相当于现在来说是获取数据回报如下的错误: {code: -500001, ts: 1529809544209} code : -500001 ts : 1529809544209 原因也简单:最新的vue2.0 webpack模板中没有dev-server.js文件,进行后台数据的模拟获取,只需要使用从接口获取数据后放在本地进行代理,页面就能拿到代理的数据了具体操作如下: before(app) { app.

基于ffmpeg+SDL2 实现简单rtsp播放器

参考资料: 编译参考:         http://blog.chinaunix.net/uid-20718335-id-2980793.html 代码参考:         http://blog.csdn.net/leixiaohua1020/article/details/8652605 实现ffmpeg在window下编译,并基于ffmpeg动态库用测试程序播放本地文件和RTSP视频流 csdn博客插个图片怎么这么麻烦,上篇辛辛苦苦截了那么多图一上传全没了,代码里想变色结果发布了一看全

基于ffmpeg网络播放器的教程与总结

基于ffmpeg网络播放器的教程与总结 一.         概述 为了解决在线无广告播放youku网上的视频.(youku把每个视频切换成若干个小视频). 视频资源解析可以从www.flvcd.com获取,此网站根据你输入的优酷的播放网页地址解析成若干个真实的视频地址. 二.         实现 首先搜索关闭网络播放器(流媒体播放器的实现方法) 得出的结论,目前主流的播放器分三大阵营微软,苹果,基于FFmpeg内核的.所以我决定从ffmpeg开源的播放器入手. 最出名的ffmpeg播放器vc

基于jQuery仿QQ音乐播放器网页版代码

基于jQuery仿QQ音乐播放器网页版代码是一款黑色样式风格的网页QQ音乐播放器样式代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div class="m_player" id="divplayer" role="application" onselectstart="return false" style="left: 0px;"> <div class=&

基于MFC的Media Player播放器的制作(3---功能实现)

|   版权声明:本文为博主原创文章,未经博主允许不得转载. 下面我们试试一下,按下退出Button退出播放器的功能: 首先,我们双击退出Button按钮,就会弹出下图的框: 上面的弄好之后我们就实现退出函数的功能: 这个代码写好之后,我们可以运行一下,在单击退出按钮,可以发现,按下之后我 们的播放器自动退出 下面我们在实现打开文件的功能,这个功能比较复杂,第一步我们首先双击打开文件按钮,在CPandaPlayerDlg.cpp中创建函 数OnOpenfile():创建过程同上. 可以看到函数:

基于MFC的Media Player播放器的制作介绍

|   版权声明:本文为博主原创文章,未经博主允许不得转载. 因为这次多媒体课程设计做一个基于MFC的播放器,因为本人实力太菜,需要播放音乐或视频文件时候,自己写不出解码 函数,所以准备使用第三方多媒体库或是第三方控件辅助播放,找来找去还是觉得用Windows Media Player控件来编写比较 方便,因此这次播放器的制作主要是根据Media Player控件来实现,因为在微软平台已经封装好了一系列的解码方法(如声音解 码和视频解码)和一些常用的操作方法(如声音音量的增加,快进等等),因此使

基于Web Assembly的H265播放器实现

项目概述 随着视频编码技术的发展,相比H.264,H.265具有同等画质体积一半.画质更清晰细腻.编码效率更高等诸多优势. 但因版权等因素主流浏览器还不支持H.265的解码,因此需要专门的插件实现解码.本项目基于Web Assembly(封装FFmpeg库).JS解封装.Canvas投影以及AudioContext,是Web端的H265播放器的完整解决方案. 播放器显示效果如下: 功能简介 播放器主要分为UI.Loader.数据处理.数据渲染四个部分和3个线程.一个是主线程,负责界面控制.下载控

ffmpeg学习——播放器解码流程 (转前编辑)

播放器解码流程 1.Demux解复用:媒体文件中音视频数据是压缩在一起的,单压缩算法不同,所以解码前需先将音视频数据解绑,解复用即将音视频数据分开 2.解码,FFmpeg中解码流程对应的API函数 Ffmpeg中Demux这一步是通过 avformat_open_input()    :读出文件的头部信息,并做demux,之后可以读取媒体文件中的音频和视频流 av_read_frame()     :从音频和视频流中读取出基本数据流packet avcodec_decode_video2():读

基于MFC的Media Player播放器的制作(4---功能实现代码)

|   版权声明:本文为博主原创文章,未经博主允许不得转载. 下面附上我整个的播放器功能实现部分的代码,如果有需要整个Project的联系我邮箱:[email protected] PandaPlayerDlg.h 1 // PandaPlayerDlg.h : header file 2 // 3 //{{AFX_INCLUDES() 4 #include "wmpplayer4.h" 5 #include "wmpcontrols.h" 6 #include &