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. [置顶] Bug 11775332 - cluvfy fails with PRVF-5636 with DNS response timeout error [ID 11775332.8]

    Bug 11775332  cluvfy fails with PRVF-5636 withDNS response timeout error but error text is not clear ...

  2. Delphi VMT的前世今生(研究一下D7的VMT表结构)

    主要是TObject那些虚函数,到底放在了哪里?

  3. 深刻:截获windows的消息并分析实例(DefWindowProc),以WM_NCHITTEST举例(Windows下每一个鼠标消息都是由 WM_NCHITTEST 消息产生的,这个消息的参数包含了鼠标位置的信息)

    1,回调函数工作机制 回调函数由操作系统自动调用,回调函数的返回值当然也是返回给操作系统了. 2,截获操作系统发出的消息,截获到后,将另外一个消息返回给操作系统,已达到欺骗操作系统的目的. 下面还是以 ...

  4. [SVN]两个分支合并

    Date:2014-1-1 Summary: 记录一下自己使用SVN时候的操作步骤,先吃鱼,再学钓鱼 Contents: 环境:从同事的branch迁出一份代码,作为自己的分支进行开发,同时同事也在自 ...

  5. Zero Clipboard - 跨浏览器兼容的“复制到剪贴板”功能

    开发中经常会用到复制的功能,在 IE 下实现比较简单,但要想做到跨浏览器比较困难了. 本文将介绍一个跨浏览器的库类 Zero Clipboard ,它利用 Flash 进行复制,所以只要浏览器装有 F ...

  6. Android Studio Gradle 添加.so 支持文件

    近期发展Android Wear 关注商品.官员Demo所有gradle 工程. 当然,我也用eclipse配置一个可行的环境. 问题来了,eclipse,android studio 开发 andr ...

  7. ORACLE:plsql优化

      1.登录后默认自动选中My Objects? 设置方法:Tools菜单--Brower Filters会打开Brower Filters的定单窗口,把“My Objects”设为默认即可.? 同理 ...

  8. Spring中继承配置的注入方法

    (1)两个java类.一个父类一个字类 package com.lc.inherit; /* * 这里是父类 */ public class Student { protected String na ...

  9. cocos2d-x3.2下使用Umeng 64位SDK注意事项

    友盟官方的样例中已经有了Cocos2d-x的Demo使用起来也是比較方便的.但在64位的版本号使用时须要注意 32位SDK改动: 将Xcode中Build Settings的Architectures ...

  10. Android_app项目开发步骤总结

    做了几个android企业应用项目后,总结了项目的基本开发步骤.希望可以交流. 一 应用规划:      ※确定功能.      ※必须的界面及界面跳转的流程.      ※须要的数据及数据的来源及格 ...