LinuxでMPEG2再生(2)

mpeg2decのソースを読んでMPEG2再生プログラムを作った。

音も出なければ、表示タイミングの同期もとれてないけど…
って、それって、mpeg2decのまんまやん。
実際表示部分を先日のSDLにすげ替えただけなんだけど
解読したことに意味があると思う。

自分がいじくったプログラムで
動画がデコードされて再生されるってのに
ちょっと感動した。

とりあえずMPEG2再生まわりはMPEG2の構造をもっと学んで
具体的な処理が決まるまで休止。

プログラムで次かかれるのはソケットプログラミングか。
Research | - | trackbacks (0)

LinuxでMPEG2再生

つまりは、プレイヤーを作るってことなのかな。

デコードはライブラリに任せることにする。
libmpeg2というのが有名っぽい。

これを使ったプレイヤーも多く、ただ再生したいのならそれらをどうぞ。

libmpeg2を使うにあたっての注意。

まずC++から使う場合はヘッダファイルのインクルードの際に

extern "C"{
#include
#include
}

のように「extern "C"」が必要。

それから、docフォルダ内のサンプルを試す場合はおそらく無音のmpeg2でないとちゃんとした画像が出力されません。

同様の理由で mpeg2dec をテストする場合
指定するファイルに音がついてるなら -s オプションで音を切り捨てないと綺麗に映像が出ません。

どれも当たり前といえばそうなんですが…。

ということで、mpeg2decのソース読んで
とりあえず映像の表示だけでもしちゃいたいです。

その際先回のSDLを使う予定。


…先回のソース、間違いだらけだったのでこっそり修正。

画面を16ビットカラーにしてぶん回してみたら
研究室のマシンで70FPS出たのでまぁよしとする。

SDL_CreateYUVOverlay()

等を使って YUV ビデオオーバレイ に描画すると
さらに表示速度を上げられるかも知れない。
Research | - | trackbacks (0)

Linuxで高速な2D描画(SDL)(2)

SDLの速度を試すと言うことでFPSを測る簡単なコードを書く。

開発には Eclipse + CDT を使った。

EclipseでSDLを使ったプログラムをコンパイルをする場合は
GCCに対して幾らかオプション指定の必要がある。

Project > Properties
から「C/C++ Build」を選び
「Configuration settings」内の

「GCC C++ Compiler」下にある
「Miscellaneous」を選び
「Other flags」のエディットボックスに
「`sdl-config --cflags`」と追記

「GCC C++ Linker」下にある
「Miscellaneous」を選び
「Linker flags」のエディットボックスに
「`sdl-config --libs`」と追記

…で動いたのだけど
何を意味しているのか良く分かっていない。
調べる必要があるなぁ。

で、簡単なソース。
ImageFunc の辺りはお遊び。

main.cpp

#include <stdlib.h>
#include "SDL.h"
#include "ImageFunc.h"

int main(int argc, char *argv[]) {

if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
exit(1);
}

atexit(SDL_Quit);

SDL_Surface *screen;

screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);

if ( screen == NULL ) {
exit(1);
}

// オフスクリーン作成
SDL_Surface* offscreen;

if (screen->format->BitsPerPixel == 16) {
offscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 480,
screen->format->BitsPerPixel,
screen->format->Rmask,
screen->format->Gmask,
screen->format->Bmask,
screen->format->Amask);
/*
printf("%d, %d, %d",
screen->format->Rmask,
screen->format->Gmask,
screen->format->Bmask);
*/
} else {
offscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 480,
32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0);
}

int frames = 0;

Uint32 beginTime = SDL_GetTicks();

int hue = 0;

for (;;) {
// イベント処理
SDL_Event event;

while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
SDL_FreeSurface(offscreen);
exit(0);
}
}

// 描画部分
// SDL_MUSTLOCK(offscreen) の結果によってはロック不要らしい
SDL_LockSurface(offscreen);

double r, g, b;

HSVToRGB(&r, &g, &b, hue, 1.0, 1.0);

// offscreen->format に従ったフォーマットで書き込むこと
if (screen->format->BitsPerPixel == 16) {
Uint16 p = ((int)(31 * r) << 11)
| ((int)(63 * g) << 5)
| ((int)(31 * b) << 0);

for (int i=0; i<640*480; i++) {
((Uint16*)(offscreen->pixels))[i] = p;
}
} else {
Uint32 p = ((int)(255 * r) << 16)
| ((int)(255 * g) << 8)
| ((int)(255 * b) << 0);

for (int i=0; i<640*480; i++) {
((Uint32*)(offscreen->pixels))[i] = p;
}
}

hue++;
hue%=360;

SDL_UnlockSurface(offscreen);

// screenにbitmapを描画
SDL_BlitSurface(offscreen, NULL, screen, NULL);

// screenの全領域を更新
SDL_UpdateRect(screen,0,0,0,0);

frames++;

Uint32 t = SDL_GetTicks();
Uint32 d = t - beginTime;

if (d >= 1000) {
int fps = frames * 1000 / d;

char title[16];
sprintf(title, "%d", fps);

SDL_WM_SetCaption(title, NULL);

beginTime = t;
frames = 0;
}
}
SDL_FreeSurface(offscreen);
return 0;
}


ImageFunc.cpp

#include "ImageFunc.h"
#include <math.h>
#include <algorithm>

void RGBToHSV(double r, double g, double b, double* h, double *s, double *v)
{
// r, g, b それぞれ [0, 1]
// h は [0,360)
// s と v が [0, 1]
// ただし s = 0 の場合 h = UNDEF
const double UNDEF = 360.0;

double max = std::max( std::max(r, g), b);
double min = std::min( std::min(r, g), b);

*v = max; // バリュー

// 彩度の計算 r, g, b すべて 0 なら彩度は 0
*s = (max != 0.0) ? ((max - min) / max) : 0.0;
if(*s == 0.0){
*h = UNDEF;
}else{
double delta = max - min;
if(r == max){
*h = (g-b) / delta;
}else if(g == max){
*h = 2.0 + (b - r) / delta;
}else if(b == max){
*h = 4.0 + (r - g) / delta;
}
*h *= 60.0;
if(*h < 0.0) *h += 360.0;
}
}


bool HSVToRGB(double *r, double *g, double *b, double h, double s, double v)
{
// h は [0, 360] または UNDEF
// s と v は [0, 1]
// r, g, b それぞれ [0, 1]

//const double UNDEF = 360.0;

if(s == 0.0){
//if(h == UNDEF){
*r = v;
*g = v;
*b = v;
//}else{
// return false;
//}
}else{
double f, p, q, t;
int i;
if(h == 360.0) h = 0.0;
h /= 60.0; // h を [0, 6) とする
i = (int)floor(h); // floor() は最大整数 <= h を返す
f = h - i; // f は h の小数部分
p = v * (1.0 - s);
q = v * (1.0 - (s * f));
t = v * (1.0 - (s * (1.0 - f)));
switch(i){
case 0: *r = v; *g = t; *b = p; break;
case 1: *r = q; *g = v; *b = p; break;
case 2: *r = p; *g = v; *b = t; break;
case 3: *r = p; *g = q; *b = v; break;
case 4: *r = t; *g = p; *b = v; break;
case 5: *r = v; *g = p; *b = q; break;
}
}
return true;
}


ImageFunc.h

void RGBToHSV(double r, double g, double b, double* h, double *s, double *v);
bool HSVToRGB(double *r, double *g, double *b, double h, double s, double v);


実行するとウィンドウが出てキャプションにFPSが出ます。

僕の環境では11FPSでした。
…というのもVirtual PC上での実行だったので。
Research | - | trackbacks (0)