显示标签为“SDL”的博文。显示所有博文
显示标签为“SDL”的博文。显示所有博文

2010年4月18日星期日

FFmpeg和SDL的API

使用FFmpeg的API和SDL的API进行视频的解码和显示,似乎还是有点技术含量的东西,我最近收到一些email询问视频的解码和显示的实现,今天hanyionet就献上博文一篇简单地说明一下如何使用这些API,其实使用这些API其实一点都不难,不要被复杂描述吓到。我们所要做就是先要了解视频的解码和显示到底是怎样的一个过程,然后了解各个API的作用。


进行解码和视频的现实一般来说就是这样的步骤:
初始化-->解码-->图像缩放-->视频显示
以下是一个简单的过程流程图,在每一个步骤中给出一些比较重要的API。

Process flow of video decode module new

可以看出,不同的步骤的实现,就是找到并使用相对应的API。
图中的API的具体说明,今天一同给出。

FFmpeg API

描述

av_register_all()

Initializes libavformat and registers all the muxers, demuxers and protocols.

avcodec_find_decoder(…)

Finds a decoder with a matching codec ID.

avcodec_alloc_context()

Allocates an AVCodecContext and sets its fields to default values.

avcodec_alloc_frame()

Allocates an AVFrame and sets its fields to default values.

sws_getContext(…)

Returns an SwsContext to be used in sws_scale().

sws_scale(…)

Scales the data in source according to our settings in our SwsContext c. srcStride and dstStride are the source and destination linesize.

avcodec_decode_video(…)

Decodes a video frame from buffer into picture.

 

SDL API

描述

SDL_SetVideoMode()

Set up a video mode with the specified width, height, and bits-per-pixel.

SDL_CreateYUVOverlay()

It is used to create a YUV overlay of the specified width, height and format for the provided display.

SDL_BlitSurface()

This performs a fast blit from the source surface to the destination surface.

SDL_FreeSurface()

Frees (deletes) a SDL surface.

SDL_UpdateRect()

Makes sure the given area is updated on the given screen.

SDL_Flip()

It is used to swap screen buffers. On hardware that supports double-buffering, this function sets up a flip and returns.

SDL_FreeYUVOverlay()

Free a YUV video overlay.

其实要理解FFmpeg的API还有一个非常重要的地方就是理解,各种数据结构的具体内容,譬如AVFrame和AVCodecContext,个人认为这两个结构是比较重要的。
了解的这些API的使用方法后,现在应该做的就是找一个例子例如ffplay.c或者http://dranger.com/ffmpeg/里的例程,体会一下,最后使用这些API搭建出属于自己的视频播放程序。

Enjoy!

2009年5月9日星期六

SDL SGE库加入TrueType功能

关于SGE库我已经在以前的日志里介绍过了。如果我们的SGE需要有TrueType 功能,简单地说就是可以在sdl surface上写入文字,还需要加入freetype这个库进行build。

The TrueType functions uses the FreeType library (v2.x). SGE的build需要freetype-2.1.10,否则不会正确build,会有一些错误。因为SGE需要譬如头文件.../freetype/nternal/ftobjs.h,而新版的freetype则不会有这个头文件。 进入http://mirrors.zerg.biz/nongnu/freetype/ 就可以找到freetype-2.1.10 ,可参考freetype-2.1.10/docs/INSTALL.UNX的帮助。

使用msys进入freetype目录依次输入

      ./configure [options]

      make

      make install           (as root)

然后就会生成正确的.a静态库文件。

使用msys需要注意一些点:

1.需要build的project的路径中不能有空格,譬如C:/Documents and Settings,否则无法识别路径。

2.cd /C/ 进入C盘,要使用反斜杠。

现在build 新的SGE库with TrueType functions。使用同样的方法,加入freetype的include路径和已经编译好的lib。

大功告成。

现在可以使用新的SGE库 with TrueType functions功能。譬如:

写一个几个字到屏幕上:

sge_TTFont *font;

/*注意要将font.ttf文件放入project的目录里*/

font=sge_TTF_OpenFont("font.ttf", 50);

/* Drawstext on screen */

sge_tt_textout(drawScreen, font, "my first SGE text", 50,100, 0,0,255, 0,0,0, 120);

还有一点要注意:因为在build SGE时要对其源文件进行一些改变。当其他project要使用已经被build的SGE的库时候不能使用SGE原始的头文件,而是要使用改变过的头文件。因为include里的.h文件,必须和参与生成dll的文件相同。不然link这个dll则会产生错误。

 

########

补充,如果要使用VS2005或以后的版本进行编译的话。

在以下网址可以下载到SGE的项目文档,然后建立VC项目。

http://www.digitalfanatics.org/cal/sge/index.html

Download SGE project files for MS Visual C/C++

 

FreeType library (v2.x).请在到以下网址下载Binaries。

http://gnuwin32.sourceforge.net/packages/freetype.htm

• Binaries
Zip
然后在将freetpye.lib加入项目的Additional Dependencies。

在sge_config.h中将注释掉这行#define _SGE_NOTTF。

这样我们的sge_config.h将如下。

/* SGE Config header (generated automatically) */

#define SGE_VER 030809

#define _SGE_C_AND_CPP

//#define _SGE_HAVE_IMG

//#define _SGE_NOTTF

接下来设定基本完成就可以进行编译了。

2009年3月23日星期一

编译SGE库

SGE是一个非常实用也挺不错的SDL图型外部库,在我的项目中我使用它进行一些简单的2D做图,并且使用它的Sprite classes。接下来简单地介绍如何编译它。

在WIN32环境下,使用MinGW+MSYS, 首先编译SDL,网上有很多帮助,然后见编译完成的SDL的静态库放入C:\MinGW\lib,将头文件放入C:\MinGW\include\SDL。

然后使用MSYS进入SGE目录,输入make就可以进行编译。如果输入make install,会Builds 一个 dynamic SGE library 并且 将SGE的 headers 放入例如C:\MinGW\include\SDL里。make 的时候可能会有错误,可以根据错误提示进行改正,例如:可能会遇到sge_surface.cpp:148: error: invalid initialization of non-const reference of type 'char*&' from a temporary of type 'char**'这样的错误,只需在sge_surface.cpp:148将va_start((va_list*)ap, format); 改成va_start((va_list&)ap, format); 即可。

 

如果以上方法有问题,或者无法编译dll库。那么可以试试以下方法 (点击下图,可看大图):

SGE_Build_Eclipse1.使用Eclipse, 然后新建一个C++项目,将SGE的源文件加入其中,如图A所示。

并新建一个sge.cpp文件,输入#include "sge.h"   int main(int argc, char** argv) {  return 0;    }

2.在setting里进行一些编译所需的简单设定如图B, C, D所示。

3.现在还没完成,如果没有SDL_image话,那么需要对sge_config.h手动进行设定,如图E所示,加入画红线的语句,去掉其上面的语句。

4.现在编译会又会遇到,sge_surface.cpp:148: error: invalid initialization of non-const reference of type 'char*&' from a temporary of type 'char**'这样的错误,同样的,如图F 所示将va_start((va_list*)ap, format); 改成va_start((va_list&)ap, format); 即可。同一类型的错误,都可以这样改正。

好了,大功告成,现在在/yourproject/Debug里你会找到SGE.DLL。

2008年12月27日星期六

setCentralWidget使用嵌入SDL的Qt Widget?

以前讨论了SDL嵌入Qt Widget, 比较规范的方法是,我在以前的文章里已经提过了:  

char variable[64]; 
_snprintf(variable, sizeof(variable), "SDL_WINDOWID=0x%lx", winId()); 
SDL_putenv(variable); 

这里只使用了三行程序,很简单,唯一要注意的一点:不要使用effectiveWinId (),而是要使用winId ()。
现在我们要使用这个已经嵌入SDL的Qt Widget, 我做了两个测试:


测试1:在MainWindow中使用setCentralWidget

SDLVideo *sdlvideo = new SDLVideo; 
setCentralWidget(sdlvideo); 


结果:无法成为MainWindow的CentralWidget,程序执行一下就立刻结束。测试2:在MainWindow中使用QDockWidget 

SDLVideo *SDLVideo_dock = new SDLVideo; 
QDockWidget *dock_a = new QDockWidget(tr("Media Player of ... ..."), this); 
dock_a->setWidget(SDLVideo_dock); 
//addDockWidget(Qt::LeftDockWidgetArea, dock_a); 
viewMenu->addAction(dock_a->toggleViewAction()); 

结果:和预料的一样,也无法成为MainWindow的QDockWidget,程序执行一下就立刻结束。
结论:经过两个测试证明,SDL嵌入Qt Widget,在一定程度上不能和一般的Qt Widget一样工作,虽然现在它也是Widget但是它只是一个“类Qt Widget”,一定程度上也是一个SDL app,它只是嵌入一个Qt Widget。原因是winid的返回值的问题,在windows下会有点问题,在linux下以上的程序应该就没有问题。

2008年12月12日星期五

利用ffmpeg和sdl库播放视频经验

首先要设定Properties for Project: 在MinGW C Linker里-->Libraries --> 加入mingw32, SDLmain, SDL, avformat, avcodec, avutil,并设定想对应的正确的Library search path,在Directories里加入所需的Include path.
然后使用http://www.dranger.com/ffmpeg/tutorial02.c上的tutorial02.c这个例子。
接下来就可以编译和Build啦,(对了,在Build artifact里Artifact Type选用Shared Library或Executable都可以 )。
最后在Command Prompt里进入debug目录输入:例如:projectname.exe examplevideo.avi 就可以播放视频了,实在很简单吧。

最后,推荐一个网站:http://www.arjanhouben.nl/SDL_ffmpeg/

2008年11月30日星期日

Qt 及SDL

Qt部分:
可以把 QWidget包成一個QDockWidget的子类,进而加到QDockWidget中,例如:

SDLVideo *SDLVideo_dock = new SDLVideo; 
QDockWidget *dock_4 = new QDockWidget(tr("Media Player of Online Tool of Robotic Experiment"), this); 
dock_4->setWidget(SDLVideo_dock); // 重点:把 QWidget包成一個QDockWidget的子类 
addDockWidget(Qt::LeftDockWidgetArea, dock_4); 
viewMenu->addAction(dock_4->toggleViewAction()); 

再介绍两个有趣的函数:

setAttribute(Qt::WA_PaintOnScreen);//这个函数可以给屏幕截图 
setUpdatesEnabled(false);//可以决定是否对Widget截的图是否可以Update 

SDL部分:

putenv("SDL_VIDEODRIVER=directx"); 

注意:这个函数必须用在SDL_Init();之前才有实际效果。来设置为directx环境。(VC下为了解除编译警告,也可使用SDL_putenv()来代替putenv(),效果都一样。)

以下程序实例--让SDL结合在Qt Widget里,摘自:http://www.guiadohardware.net/comunidade/showthread.php?t=797107
我试了,可以用,但是还不是很完美的解决方案。
如何用SDL创建一个窗口: 一个台湾网友的LinuxGame的博客,中文说明http://otlinux.blogspot.com/2007_12_01_archive.html

英文版http://www.aaroncox.net/tutorials/2dtutorials/sdlwindow.html

如何让SDL嵌入到Qt的Widget里,使用:QWidget::winId()
至今为止,最好的解决方案。例1: http://listas.apesol.org/pipermail/sdl-libsdl.org/2005-September/051604.html

#define NEED_SDL_GETENV 
#include 
//.... 
char variable[256]; 
sprintf(variable, "SDL_WINDOWID=0x%lx", winId()); 
if (SDL_putenv(variable) == -1) 
{ 
// .... 
}

例2:http://stackoverflow.com/questions/118659/how-do-i-use-qt-and-sdl-together

// Set the new video mode with the new window size 
char variable[64]; 
snprintf(variable, sizeof(variable), "SDL_WINDOWID=0x%lx", winId()); 
putenv(variable); 
// ffmpeg is relatively simple. 
// A while back, I used the page below as a reference 
// and coded up a simple app that uses ffmpeg to decode frames 
// and paints them on screen in a QWidget. 

http://www.inb.uni-luebeck.de/~boehme/libavcodec_update.html

2008年11月29日星期六

SDL库在Qt .pro中设定

在.pro 里加上以下的Script:
INCLUDEPATH = "C:\SDL-devel-1.2.13-mingw32\SDL-1.2.13\include\SDL"
win32:LIBS += -L"C:\MinGW\lib" -lmingw32 \
-L"C:\SDL-devel-1.2.13-mingw32\SDL-1.2.13\lib" -lSDLmain -lSDL
注意1: INCLUDEPATH的双引号可加可不加,win32:LIBS的双引号最好加上

2:win32:LIBS加入的顺序是很重要的

3:用 \ 和 / 效果是一样的对于连接

4:不同的文档用 \ 相隔

5:当写-L时,写-lSDLmain而不是libSDLmain.a 等等,注意写的规范性。

举一个实例:让使用Qt的项目(使用MinGW gcc)可以编译SDL_image
1.在.pro中加入
INCLUDEPATH = C:\SDL_image-1.2.7\include
win32:LIBS += C:\SDL_image-1.2.7\lib\SDL_image.lib
2.将C:\SDL_image-1.2.7\lib中的.dll文件拷到C:\WINDOWS\system32里去
3.在所需的C++文件中加入头文件:#include "SDL_image.h"



2008年11月25日星期二

在Eclipse建立SDL Extension Libraries

在Eclipse建立SDL Extension Libraries (Setting up SDL Extension Libraries in Eclipse)
从http://www.libsdl.org/下载 SDL Windows development library
每一个 extension libary 有三个主要部分:

1. The header file.
2. The lib file.
3. The *.dll file(s)

将 header file 存到 MinGW include folder. It should be at C:\MinGW\include\SDL.
将lib file 存到MinGW lib folder. The MinGW lib folder should be at C:\MinGW\lib.
再 提取 *.dll file(s) 到 C:\WINDOWS\SYSTEM32 (This is so whenever you make an SDL extension app, the program will be able to find the *.dll file(s) even if they're is not in the same directory as the *.exe)

但是存放.lib 和头文件的位置也不用和上面所说的一样,但是要记住放置的位置:)


SDL是用C编写的,但是也支持C++,同时其他多种语言,太好了,我们可以用自己熟悉的语言使用它。我在以后的实例中使用C++来使用它。

现在在Eclipse中进行一些设定:
properties --> C/C++ build --> Setting --> GCC Compiler --> Directories --> Include paths (-I) --> 加入所有需要的Include
properties --> C/C++ build --> Setting --> MinGW C Linker --> Libraries --> Include search path (-L) --> 加入所有需要的Library的Path --> 在Libraries (-I)里加入 mingw32 SDLmain SDL 请注意:要依次加入!!

linker的名称为 :
-lmingw32
-lSDLmain
-lSDL

另一个值得注意的点:#include 的写法,因为我在properties --> C/C++ build --> Setting --> GCC Compiler --> Directories --> Include paths 只写了例如:C:\SDL-devel-1.2.13-mingw32

如果使用的是Qt Eclipse Integration,就不需要进行以上操作,只需对.pro文档进行设定,在.pro文档中加入SDL的include和lib名称和路径。

2008年11月18日星期二

如何让SDL窗口嵌入Qt窗口

先简单介绍一下SDL:

SDL(Simple DirectMedia Layer)是一套开放原始码的跨平台多媒体开发函式库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函式,让开发者只要用相同或是相似的程式码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软体。目前SDL多用于开发游戏、模拟器、媒体播放器等多媒体应用领域。
虽然SDL时常被比较为‘跨平台的DirectX’,然而事实上SDL是定位成以精简的方式来完成基础的功能,它大幅度简化了控制图像、声音、输出入等工作所需撰写的程式码。但更高阶的绘图功能或是音效功能则需搭配OpenGL和OpenAL等API来达成。另外它本身也没有方便建立GUI的函式。

但是如何让SDL窗口嵌入Qt的Widget里(render videos, audioes and images under GUI(made of Qt) using SDL. The sdl screen must be successfully integrated into qt screen.) ?
(Implement SDL in a QT widget-- how to integrate SDL into Qt? )
有两种方法用于解决这个问题,一个是间接法如 solution 1 ,一个是直接法如 solution 2. 以下是从网上收集的说明。

Solution 1: Using a seperate thread for rendering:

The easiest and sanest solution would be to decouple both parts. So that SDL and Qt run in separate processes and have them use some kind of messaging to communicate. SDL can be rendered into borderless window and the editor sends commands via messages.

using a seperate thread for rendering.
This thread could run on its own in the background and you simply could use your Qt-buttons to stop/pause/resume the thread.

If you want your SDL-window to react when a real key is pressed, it would be a viable solution to simulate key events from Qt.

If you want to just signal the SDL-code in some way I'd suggest using custom events (SDL_UserEvent).
For example, do something like this:

  1. Start App and open Qt-Window
  2. Initialize SDL and open output window
  3. Create thread that updates SDL-Window waits for some signal to stop/pause/resume or for xx seconds
  4. Use the SLOTs called by your Qt-Buttons to signal the thread to stop/pause/resume (using Key- or UserEvents? or using flags being set by Qt's main-thread) [/list=1]
Solusion 2: Direct way to integrate SDL into Qt:

put the SDL overlay window on the top of Qt window by using the following 3 steps.
1) create SDL window according to the size of Qt window.
2) create SDL window without frame (SDL_NOFRAME).
3) move SDL window based on the top-right coop. of SDL window (xMoveWindow())

Following functions from SDL are mainly used,
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
SDL_GetWMInfo(&info);
p_container->embed(info.info.x11.wmwindow, false).