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的播放器的更多相关文章

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

    基于ffmpeg网络播放器的教程与总结   一.         概述 为了解决在线无广告播放youku网上的视频.(youku把每个视频切换成若干个小视频). 视频资源解析可以从www.flvcd. ...

  2. FFmpeg简易播放器的实现-视频播放

    本文为作者原创:https://www.cnblogs.com/leisure_chn/p/10047035.html,转载请注明出处 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...

  3. FFmpeg简易播放器的实现-音视频播放

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10235926.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...

  4. FFmpeg简易播放器的实现-音频播放

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10068490.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...

  5. FFmpeg简易播放器的实现-最简版

    本文为作者原创:https://www.cnblogs.com/leisure_chn/p/10040202.html,转载请注明出处 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...

  6. FFmpeg简易播放器的实现-音视频同步

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10284653.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...

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

    基于jQuery仿QQ音乐播放器网页版代码是一款黑色样式风格的网页QQ音乐播放器样式代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div class="m ...

  8. iOS之基于FreeStreamer的简单音乐播放器(模仿QQ音乐)

    代码地址如下:http://www.demodashi.com/demo/11944.html 天道酬勤 前言 作为一名iOS开发者,每当使用APP的时候,总难免会情不自禁的去想想,这个怎么做的?该怎 ...

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

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. 下面我们试试一下,按下退出Button退出播放器的功能: 首先,我们双击退出Button按钮,就会弹出下图的框: 上面的弄好之后我们就实现 ...

随机推荐

  1. 96 Stocks APIs: Bloomberg, NASDAQ and E*TRADE

      Our API directory now includes 96 stocks APIs. The newest is the Eurex VALUES API. The most popula ...

  2. centos下chm阅读器

    xchm kchmviewer chmsee

  3. POJ 1166 The Clocks

    高斯消元法第四个冠军,这个称号是非常令人兴奋~~ 题目大意: 给出9个钟表的状态.给出九种操作,问最少要操作几次能把全部的钟表调回12点. 解题思路: 对于9个钟表分别列方程,然后高斯消元就可以.因为 ...

  4. cURL安装和使用笔记

    0.前言     cURL是一个利用URL语法在命令行下工作的文件传输工具.它支持文件上传和下载,所以是综合传输工具,但习惯称cURL为下载工具.cURL还包含了用于程序开发的libcurl.cURL ...

  5. SQL查询语句联系

    建立四个表,分别是学生表,课程表,成绩表和教师信息表 插入信息: 题目: 1. 查询Student表中的所有记录的Sname.Ssex和Class列 select Sname,Ssex,Class f ...

  6. 数据挖掘 决策树算法 ID3 通俗演绎

    决策树是对数据进行分类,以此达到预測的目的.该决策树方法先依据训练集数据形成决策树,假设该树不能对全部对象给出正确的分类,那么选择一些例外添�到训练集数据中,反复该过程一直到形成正确的决策集.决策树代 ...

  7. ASP.NET MVC的跳转攻击问题

    在ASP.NET MVC的自带的模板代码中,有这样一段,用来拦截非登录用户,使其跳转到登录页面,然后登录后在跳转回原页面.所以,期间有一个returnUrl参数用来保存原页面地址.在Login Act ...

  8. Cocos2dx 3.0 过渡篇(二十六)C++11多线程std::thread的简单使用(上)

    昨天练车时有一MM与我交替着练,聊了几句话就多了起来,我对她说:"看到前面那俩教练没?老色鬼两枚!整天调戏女学员."她说:"还好啦,这毕竟是他们的乐趣所在,你不认为教练每 ...

  9. android greenDao SQLite数据库操作使用的工具

    关于如何建立类生成一个演示project.今天介绍如何使用. 这是ExampleDaoGeneratorproject代码,做了一些改动 /* * Copyright (C) 2011 Markus ...

  10. POJ 2151 Check the difficulty of problems (动态规划-可能DP)

    Check the difficulty of problems Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4522   ...