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. 八皇后问题详细分析与解答(递归法解答,c#语言描述)

    八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题.该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或 ...

  2. visual studio 2012 使用 git/github

    Visual studio 2012 除了支持自己的TFS还支持Git,这里讲的原生的支持,相比让VS2010支持Git要简单的多,仅仅需要两步: 第一步 安装工具: Microsoft.TeamFo ...

  3. SVNKit getFileFromSVN

    /* * ==================================================================== * Copyright (c) 2004-2011 ...

  4. ssh-copy-id -i ~/.ssh/id_rsa.pub admin@172.17.42.66

    ssh-copy-id -i ~/.ssh/id_rsa.pub admin@172.17.42.66

  5. SilkTest高级进阶系列9 – 异步执行命令

    我们常常会使用sys_execute函数执行一些外部的程序或者命令来做一些事情,但是由于sys_execute是一个同步的函数,它会等待执行的命令完成后才会返回.在大多数情况下,这个函数足够用了. 但 ...

  6. UML中类图的符号解释

    在UML的定义中,描写叙述类和对象之间的关系,包含下面几种方式:依赖(Dependency).关联(Association).聚合(Aggregation).组合(Composition).泛化(Ge ...

  7. 连载:面向对象葵花宝典:思想、技巧与实践(28) - 设计原则:内聚&amp;耦合

    前面通过实例解说了一个一环扣一环的面向对象的开发流程:用例模型 -> 领域模型 -> 设计模型(类模型 + 动态模型),解答了面向对象怎样做的问题.接下来我们就要讲"怎样做好面向 ...

  8. contiki etimer部分

    1.前言     contiki是一款小型开源,易于移植的多任务操作系统,专门为无线传感网设计,适合内存受限制的网络系统.国内的研究和应用还处于初级阶段,甚至还不知道这个contiki如何发音,也没有 ...

  9. Enum的简单了解

    Enum可以将一组具名的有限集合创建成一种新的类型,而这些具名的值可以作为常规的程序组件使用. 在创建enum时,编译器会为你生成一个相关的类,这个类继承自java.lang.Enum,所以enum本 ...

  10. oracle 之 内存—鞭辟近里(二)

    overview of the pga pga是在操作系统的进程或是线程特定的一块内存区域,它不是共享的.因为pga是进程指定的,因此它不会在sga中分配. pga是一个内存堆,其中包含了被专用服务器 ...