Page 6 of 8
didn't turn off mipmap
Posted: Wed Jan 10, 2007 4:41 pm
by juliusctw
Oh I never disabled mip map, maybe that's causing the performance problem, my image is also 24 bit but it keeps changing to 32 bit
I think i forgot this ,
driver->setTextureCreationFlag(ETCF_ALWAYS_32_BIT, false );
i'll give this a try and let you guys know
Here my code and my problem
Posted: Thu Jan 11, 2007 3:27 am
by juliusctw
My linux movie player
it plays fine, after i remove the mip map now it runs at 12 frames a sec, but its still too slow, the bottle neck is that i have to recreate ITexture everytime and delete ITexture every time at DumpFrame. Any suggestion on performance improvement will help greatly.
Here's the cpp file
Code: Select all
#include "IrrlichtMediaPlayer.h"
#include <ffmpeg/avcodec.h>
#include <ffmpeg/avformat.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
// compile with:
// windows:
// g++ -o player IrrlichtMediaPlayer.cpp -lavformat -lavcodec -lavutil -lz -I/c/code/iamar/irrlicht-1.2/include/ -L/c/code/iamar/irrlicht-1.2/bin/Win32-gcc/ -lIrrlicht
//
// linux:
// g++ -o player IrrlichtMediaPlayer.cpp -lavformat -lavcodec -lavutil -lz -I../irrlicht/include/ -L../irrlicht -lIrrlicht -lGL -lGLU -lXxf86vm -lXext -lX11
bool IrrlichtMediaPlayer::GetNextFrame(AVFormatContext *pFormatCtx,
AVCodecContext *pCodecCtx,
int videoStream,
AVFrame *pFrame)
{
static AVPacket packet;
static int bytesRemaining=0;
static uint8_t *rawData;
static bool fFirstTime=true;
int bytesDecoded;
int frameFinished;
// First time we're called, set packet.data to NULL to indicate it
// doesn't have to be freed
if(fFirstTime)
{
fFirstTime=false;
packet.data=NULL;
}
// Decode packets until we have decoded a complete frame
while(true)
{
// Work on the current packet until we have decoded all of it
while(bytesRemaining > 0)
{
// Decode the next chunk of data
bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame,
&frameFinished, rawData, bytesRemaining);
// Was there an error?
if(bytesDecoded < 0)
{
fprintf(stderr, "Error while decoding frame\n");
return false;
}
bytesRemaining-=bytesDecoded;
rawData+=bytesDecoded;
// Did we finish the current frame? Then we can return
if(frameFinished)
return true;
}
// Read the next packet, skipping all packets that aren't for this
// stream
do
{
// Free old packet
if(packet.data!=NULL)
av_free_packet(&packet);
// Read new packet
if(av_read_packet(pFormatCtx, &packet)<0)
goto loop_exit;
} while(packet.stream_index!=videoStream);
bytesRemaining=packet.size;
rawData=packet.data;
}
loop_exit:
// Decode the rest of the last frame
bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,
rawData, bytesRemaining);
// Free last packet
if(packet.data!=NULL)
av_free_packet(&packet);
return frameFinished!=0;
}
void IrrlichtMediaPlayer::DumpFrame(AVFrame *pFrame,
int width,
int height,
int iFrame)
{
//unsigned char *buf = (unsigned char *)malloc(sizeof(unsigned char) * 3*height*width);
static char first_time = 1;
if(first_time)
{
CurrentImage = IrrVideoDriver->createImageFromData(irr::video::ECF_R8G8B8,
irr::core::dimension2d<irr::s32>(width, height),
pFrame->data[0],
true);
first_time = 0;
}
//This is the bottle neck because I have to recreate ITexture every time
CurrentTexture = IrrVideoDriver->addTexture("movie", CurrentImage);
IrrVideoDriver->draw2DImage(CurrentTexture,
irr::core::position2d<irr::s32>(0,0),
irr::core::rect<irr::s32>(0, 0, width, height),
0);
IrrVideoDriver->removeTexture(CurrentTexture);
}
IrrlichtMediaPlayer::IrrlichtMediaPlayer(irr::video::IVideoDriver *irrVideoDriver, irr::ITimer *timer)
: IrrVideoDriver(irrVideoDriver), Timer(timer)
{
// Register all formats and codecs
av_register_all();
}
IrrlichtMediaPlayer::~IrrlichtMediaPlayer() {
// Free the RGB image
if(Buffer != NULL)
delete [] Buffer;
if(FrameRGB != NULL)
av_free(FrameRGB);
// Free the YUV frame
if(Frame != NULL)
av_free(Frame);
// Close the codec
if(CodecCtx != NULL)
avcodec_close(CodecCtx);
// Close the video file
if(FormatCtx != NULL)
av_close_input_file(FormatCtx);
}
bool IrrlichtMediaPlayer::open(char *filename) {
// Open video file
if(av_open_input_file(&FormatCtx, filename, NULL, 0, NULL)!=0)
return false; // Couldn't open file
// Retrieve stream information
if(av_find_stream_info(FormatCtx)<0)
return false; // Couldn't find stream information
// Dump information about file onto standard error
dump_format(FormatCtx, 0, filename, false);
// Find the first video stream
VideoStream=-1;
for(int i=0; i<FormatCtx->nb_streams; i++)
if(FormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)
{
VideoStream=i;
break;
}
if(VideoStream==-1)
return false; // Didn't find a video stream
// Get a pointer to the codec context for the video stream
CodecCtx=FormatCtx->streams[VideoStream]->codec;
// Get the seconds/frame of this video stream
SecondsPerFrame = (double)FormatCtx->streams[VideoStream]->r_frame_rate.den / FormatCtx->streams[VideoStream]->r_frame_rate.num;
printf("seconds per frame: %f\n", SecondsPerFrame);
// Find the decoder for the video stream
Codec=avcodec_find_decoder(CodecCtx->codec_id);
if(Codec==NULL)
return false; // Codec not found
// Inform the codec that we can handle truncated bitstreams -- i.e.,
// bitstreams where frame boundaries can fall in the middle of packets
if(Codec->capabilities & CODEC_CAP_TRUNCATED)
CodecCtx->flags|=CODEC_FLAG_TRUNCATED;
// Open codec
if(avcodec_open(CodecCtx, Codec)<0)
return false; // Could not open codec
// Allocate video frame
Frame=avcodec_alloc_frame();
// Allocate an AVFrame structure
FrameRGB=avcodec_alloc_frame();
if(FrameRGB==NULL)
return false;
// Determine required buffer size and allocate buffer
NumBytes=avpicture_get_size(PIX_FMT_RGB24,
CodecCtx->width,
CodecCtx->height);
Buffer=new uint8_t[NumBytes];
// Assign appropriate parts of buffer to image planes in pFrameRGB
avpicture_fill((AVPicture *)FrameRGB, Buffer, PIX_FMT_RGB24,
CodecCtx->width, CodecCtx->height);
return true;
}
bool IrrlichtMediaPlayer::play() {
// Read frames
static int i=0;
if(i > 1000)
return false;
//if(Timer->getRealTime() - PreviousDrawTime > (SecondsPerFrame*1000))
//{
if(GetNextFrame(FormatCtx, CodecCtx, VideoStream, Frame))
{
img_convert((AVPicture *)FrameRGB, PIX_FMT_RGB24, (AVPicture*)Frame,
CodecCtx->pix_fmt, CodecCtx->width, CodecCtx->height);
printf("dumping frame %d\n", i);
// Dump the frame
DumpFrame(FrameRGB, CodecCtx->width, CodecCtx->height, i);
i++;
}
PreviousDrawTime = Timer->getRealTime();
//}
return true;
}
bool IrrlichtMediaPlayer::stop() {
return true;
};
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
int main(int argc, char *argv[])
{
IrrlichtDevice *device =
createDevice( video::EDT_OPENGL, dimension2d<s32>(800, 600), 16,
false, false, false, 0);
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
IrrlichtMediaPlayer imp(driver, device->getTimer());
if(! imp.open("test_movie.avi"))
{
printf("problem opening movie");
exit(1);
}
driver->setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);
driver->setTextureCreationFlag(ETCF_ALWAYS_32_BIT, false);
while(device->run())
{
static int i = 0;
driver->beginScene(true, true, SColor(255,100,101,140));
imp.play();
//smgr->drawAll();
driver->endScene();
}
device->drop();
return 0;
}
Here is the header file
Code: Select all
#ifndef __IRRLICHT_MEDIA_PLAYER_H__
#define __IRRLICHT_MEDIA_PLAYER_H__
// irrlicht includes
#include "irrlicht.h"
// ffmpeg includes
#include <ffmpeg/avcodec.h>
#include <ffmpeg/avformat.h>
class IrrlichtMediaPlayer {
private:
irr::ITimer *Timer;
irr::video::IVideoDriver *IrrVideoDriver;
irr::video::IImage *CurrentImage;
irr::video::ITexture *CurrentTexture;
unsigned long PreviousDrawTime;
double SecondsPerFrame;
AVFormatContext *FormatCtx;
int VideoStream;
AVCodecContext *CodecCtx;
AVCodec *Codec;
AVFrame *Frame;
AVFrame *FrameRGB;
int NumBytes;
uint8_t *Buffer;
bool GetNextFrame(AVFormatContext *pFormatCtx,
AVCodecContext *pCodecCtx,
int videoStream,
AVFrame *pFrame);
void DumpFrame(AVFrame *pFrame,
int width,
int height,
int iFrame);
public:
// constructor
IrrlichtMediaPlayer(irr::video::IVideoDriver *irrVideoDriver,
irr::ITimer *timer);
// destructor
~IrrlichtMediaPlayer();
// functions to open, play, and stop the media
bool open(char *filename);
bool play();
// make a "close" function
bool stop();
};
#endif
Posted: Thu Jan 11, 2007 8:22 am
by hybrid
Just as I said: Use only one (permanent) texture and make use of lock and unlock.
finally profiled the problem
Posted: Thu Jan 11, 2007 6:18 pm
by juliusctw
ok after digging into the source code, I found out that each time I create a new ITexture, I was calling copyToScaling which is probably the slowest algorithm inside irrlicht.
Hybrid suggested that I should just create a single ITexture, use lock to get the pointer to the data, and then write the new IImage into that buffer. I have been trying to do that the whole time,,,,, I knew that already....
the problem for me is that it seems to me that regardless, I would still have to re Scale the image every frame b/c the movie is not in optimum power of two. So does that mean that every single frame, I would have to scale the frame before writing to the buffer.
But I don't think that will provide as much performance boost as expected since I am still scaling the image. Is there a way which I don't scale the image???
or perhaps I should write my own faster scaling function? Emil how did you deal with non power of 2 movies????
I tried to read copyToScaling inside CImage, but i don't really understand it, i think it scales the image to the power of two? is that the case??? Or does it maintain the original size and writes transparent bytes to the rest of them to fill up the buffer?
Why do we even need to scale the image in the first place? Does openGL "requires" power of two images?
Posted: Thu Jan 11, 2007 8:06 pm
by hybrid
You have to set up a texture which is at least as large as your movie and then copy line by line, with proper padding of each line (i.e. skip the rest of each line). Then use texture coords which use only the part of the texture which shows the movie.
alright i'll do that
Posted: Fri Jan 12, 2007 6:08 am
by juliusctw
alright, i'll give that a try and report back when i'm done , thanks
i did it
Posted: Tue Jan 16, 2007 1:41 am
by juliusctw
Ok , i followed your instruction, and now i have fps to 21 fps, it is still kinda slow, but now my major concern is that Irrlicht for some reason scales the movie to a different size, are you familiar with that?
Posted: Tue Jan 16, 2007 12:46 pm
by hybrid
You could profile your app to see what is happening, or simply debug.
ok, i got it
Posted: Tue Jan 23, 2007 4:54 am
by juliusctw
Ok
quick update
I finally got the speed I want, but now I have decode problem, some of the frames are badly decoded, mpeg2 works fine, but xvid with frames that change quicks are messed up, i'll fix that next
i am so stuck
Posted: Wed Jan 24, 2007 6:47 am
by juliusctw
does anybody have experience with libav ?? I am very stuck ,
everything seems fine, but some times, the libav load frame function won't read the entire frame? anybody?
It all works now
Posted: Thu Jan 25, 2007 3:55 pm
by juliusctw
Great news
The linux movie player all works now, it plays divx, xvid, ogg, basically everything FFMPEG. I actually wrote 2 versions, one works in linux and the other on windows as well, sorry apple people
I'll write a cleaner version and post it later.
Posted: Thu Jan 25, 2007 7:29 pm
by Emil_halim
that is a good news .
i want top tell you some thing about the speed of movie, with my Nvidia 5200FX , the lock and unlock and writing to texture under DirctX9 is much faster then OpenGL when playing the same movie in each driver.
any way , Keep up your good work.
Posted: Tue Mar 13, 2007 4:30 pm
by hansel
Ey
I'm triying to improve the Linux movie player, now it's using lock and unlock functions instead of creating a texture every frame. The framerate playing a 640x480 Divx 5 movie is now 350 fps using a nvidia 7300 Gs, I think it's a real improvement compared to the past
I just need help to create the pause (not really, It's just to stop playing xDD), stop, replay (loop) functions and getting some stability with Ati cards. Someone is interesed?
videoPlayer.h
Code: Select all
#ifndef __VIDEO_PLAYER_H__
#define __VIDEO_PLAYER_H__
// irrlicht includes
#include "irrlicht.h"
// ffmpeg includes
#include <ffmpeg/avcodec.h>
#include <ffmpeg/avformat.h>
using namespace irr;
class cVideoPlayer
{
private:
irr::ITimer *Timer;
irr::video::IVideoDriver *IrrVideoDriver;
irr::video::IImage *CurrentImage;
irr::video::ITexture *CurrentTexture;
unsigned long lastTime;
double SecondsPerFrame;
AVFormatContext *FormatCtx;
int VideoStream;
AVCodecContext *CodecCtx;
AVCodec *Codec;
AVFrame *Frame;
AVFrame *FrameRGB;
int NumBytes;
uint8_t *Buffer;
bool GetNextFrame(AVFormatContext *pFormatCtx,
AVCodecContext *pCodecCtx,
int videoStream,
AVFrame *pFrame);
bool DumpFrame(AVFrame *pFrame, int width, int height);
s32* p;
s32* pimage;
public:
// constructor
cVideoPlayer(irr::video::IVideoDriver *irrVideoDriver,
irr::ITimer *timer);
cVideoPlayer(irr::video::IVideoDriver *irrVideoDriver,
irr::ITimer *timer, char* filename);
// destructor
~cVideoPlayer();
// functions to open, play, and stop the media
bool open(char *filename);
bool play();
// make a "close" function
bool stop();
irr::video::ITexture* getVideoTexture();
void drawVideoTexture();
};
#endif
videoPlayer.cpp
Code: Select all
#include "videoPlayer.h"
#include <ffmpeg/avcodec.h>
#include <ffmpeg/avformat.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
// Original code by: juliusctw
// Modified by Hansel
// compile with:
// windows:
// g++ -o player cVideoPlayer.cpp -lavformat -lavcodec -lavutil -lz -I/c/code/iamar/irrlicht-1.2/include/ -L/c/code/iamar/irrlicht-1.2/bin/Win32-gcc/ -lIrrlicht
//
// linux:
// g++ -o player cVideoPlayer.cpp -lavformat -lavcodec -lavutil -lz -I../irrlicht/include/ -L../irrlicht -lIrrlicht -lGL -lGLU -lXxf86vm -lXext -lX11
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
cVideoPlayer::cVideoPlayer(irr::video::IVideoDriver *irrVideoDriver, irr::ITimer *timer)
: IrrVideoDriver(irrVideoDriver), Timer(timer)
{
IrrVideoDriver->setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);
IrrVideoDriver->setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true);
// Register all formats and codecs
av_register_all();
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
cVideoPlayer::cVideoPlayer(irr::video::IVideoDriver *irrVideoDriver, irr::ITimer *timer, char* filename)
: IrrVideoDriver(irrVideoDriver), Timer(timer)
{
IrrVideoDriver->setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);
IrrVideoDriver->setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true);
// Register all formats and codecs
av_register_all();
if (! open(filename))
{
printf("problem opening movie");
exit(1);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
cVideoPlayer::~cVideoPlayer()
{
// Free the RGB image
if (Buffer != NULL)
delete [] Buffer;
if (FrameRGB != NULL)
av_free(FrameRGB);
// Free the YUV frame
if (Frame != NULL)
av_free(Frame);
// Close the codec
if (CodecCtx != NULL)
avcodec_close(CodecCtx);
// Close the video file
if (FormatCtx != NULL)
av_close_input_file(FormatCtx);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::open(char *filename)
{
// Open video file
if (av_open_input_file(&FormatCtx, filename, NULL, 0, NULL)!=0)
return false; // Couldn't open file
// Retrieve stream information
if (av_find_stream_info(FormatCtx)<0)
return false; // Couldn't find stream information
// Dump information about file onto standard error
dump_format(FormatCtx, 0, filename, false);
// Find the first video stream
VideoStream=-1;
for (int i=0; i<FormatCtx->nb_streams; i++)
if (FormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)
{
VideoStream=i;
break;
}
if (VideoStream==-1)
return false; // Didn't find a video stream
// Get a pointer to the codec context for the video stream
CodecCtx=FormatCtx->streams[VideoStream]->codec;
// Get the seconds/frame of this video stream
SecondsPerFrame = (double)FormatCtx->streams[VideoStream]->r_frame_rate.den / FormatCtx->streams[VideoStream]->r_frame_rate.num;
printf("Duration: %f", (double)FormatCtx->duration);
printf(" seconds per frame: %f\n", SecondsPerFrame);
// Find the decoder for the video stream
Codec=avcodec_find_decoder(CodecCtx->codec_id);
if (Codec==NULL)
return false; // Codec not found
// Inform the codec that we can handle truncated bitstreams -- i.e.,
// bitstreams where frame boundaries can fall in the middle of packets
if (Codec->capabilities & CODEC_CAP_TRUNCATED)
CodecCtx->flags|=CODEC_FLAG_TRUNCATED;
// Open codec
if (avcodec_open(CodecCtx, Codec)<0)
return false; // Could not open codec
// Allocate video frame
Frame=avcodec_alloc_frame();
// Allocate an AVFrame structure
FrameRGB=avcodec_alloc_frame();
if (FrameRGB==NULL)
return false;
// Determine required buffer size and allocate buffer
NumBytes=avpicture_get_size(PIX_FMT_RGB32,
CodecCtx->width,
CodecCtx->height);
Buffer=new uint8_t[NumBytes];
// Assign appropriate parts of buffer to image planes in pFrameRGB
avpicture_fill((AVPicture *)FrameRGB, Buffer, PIX_FMT_RGB32,
CodecCtx->width, CodecCtx->height);
return true;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::play()
{
// Read frames
static int i=0;
if (i > 1000000) return false;
if (Timer->getRealTime() - lastTime > (SecondsPerFrame*1000))
{
if (GetNextFrame(FormatCtx, CodecCtx, VideoStream, Frame))
{
img_convert((AVPicture *)FrameRGB, PIX_FMT_RGB32, (AVPicture*)Frame,
CodecCtx->pix_fmt, CodecCtx->width, CodecCtx->height);
printf("dumping frame %d\n", i);
// Dump the frame
DumpFrame(FrameRGB, CodecCtx->width, CodecCtx->height);
i++;
}
lastTime = Timer->getRealTime();
}
return true;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::stop()
{
return true;
};
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::GetNextFrame(AVFormatContext *pFormatCtx,
AVCodecContext *pCodecCtx,
int videoStream,
AVFrame *pFrame)
{
static AVPacket packet;
static int bytesRemaining=0;
static uint8_t *rawData;
static bool fFirstTime=true;
int bytesDecoded;
int frameFinished;
// First time we're called, set packet.data to NULL to indicate it
// doesn't have to be freed
if (fFirstTime)
{
fFirstTime=false;
packet.data=NULL;
}
// Decode packets until we have decoded a complete frame
while (true)
{
// Work on the current packet until we have decoded all of it
while (bytesRemaining > 0)
{
// Decode the next chunk of data
bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame,
&frameFinished, rawData, bytesRemaining);
// Was there an error?
if (bytesDecoded < 0)
{
fprintf(stderr, "Error while decoding frame\n");
return false;
}
bytesRemaining-=bytesDecoded;
rawData+=bytesDecoded;
// Did we finish the current frame? Then we can return
if (frameFinished)
return true;
}
// Read the next packet, skipping all packets that aren't for this
// stream
do
{
// Free old packet
if (packet.data!=NULL)
av_free_packet(&packet);
// Read new packet
if (av_read_packet(pFormatCtx, &packet)<0)
goto loop_exit;
}
while (packet.stream_index!=videoStream);
bytesRemaining=packet.size;
rawData=packet.data;
}
loop_exit:
// Decode the rest of the last frame
bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,
rawData, bytesRemaining);
// Free last packet
if (packet.data!=NULL)
av_free_packet(&packet);
return frameFinished!=0;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::DumpFrame(AVFrame *pFrame,
int width,
int height)
{
//unsigned char *buf = (unsigned char *)malloc(sizeof(unsigned char) * 3*height*width);
static char first_time = 1;
if (first_time)
{
CurrentImage = IrrVideoDriver->createImageFromData(irr::video::ECF_A8R8G8B8,
irr::core::dimension2d<irr::s32>(width, height),
pFrame->data[0],
true);
first_time = 0;
CurrentTexture = IrrVideoDriver->addTexture("movie", CurrentImage);
}
p = (s32*)CurrentTexture->lock ();
pimage = (s32*)CurrentImage->lock ();
for (int i = 0; i < width*height; i++) p[i] = pimage[i];
// unlock de texture and the image
CurrentTexture->unlock();
CurrentImage->unlock();
return true;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
irr::video::ITexture* cVideoPlayer::getVideoTexture()
{
return CurrentTexture;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
void cVideoPlayer::drawVideoTexture()
{
// draw the texture
IrrVideoDriver->draw2DImage(CurrentTexture, irr::core::position2d<irr::s32>(0,0),
irr::core::rect<irr::s32>(0,0,1024,768), 0, irr::video::SColor(255,255,255,255), true);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
main.cpp
Code: Select all
#include "videoPlayer.h"
#include <stdio.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
using namespace irr;
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
IrrlichtDevice *device;
IVideoDriver* driver;
ISceneManager* smgr;
class MyEventReceiver : public IEventReceiver
{
public:
virtual bool OnEvent(SEvent event)
{
/*
If the key 'W' or 'S' was left up, we get the position of the scene node,
and modify the Y coordinate a little bit. So if you press 'W', the node
moves up, and if you press 'S' it moves down.
*/
if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case KEY_KEY_A:
printf("-> Key A\n");
break;
return true;
}
}
return false;
}
};
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
MyEventReceiver receiver;
device = createDevice( video::EDT_OPENGL, dimension2d<s32>(640, 480), 32, false, false, false, &receiver);
driver = device->getVideoDriver();
smgr = device->getSceneManager();
// initialise the videoPlayer with a filename
cVideoPlayer* videoPlayer = new cVideoPlayer(driver, device->getTimer(), "Futurama.avi");
// to get the framerate (fps)
int lastFPS = -1;
while (device->run())
{
static int i = 0;
driver->beginScene(true, true, SColor(255,100,101,140));
// play the video
videoPlayer->play();
// draw the texture in a rectangle
videoPlayer->drawVideoTexture();
//smgr->drawAll();
driver->endScene();
// show the framerate (fps)
int fps = driver->getFPS();
if (lastFPS != fps)
{
wchar_t tmp[1024];
swprintf(tmp, 1024, L"Video Example - Irrlicht Engine [%ls] fps: %d",
driver->getName(), fps);
device->setWindowCaption(tmp);
lastFPS = fps;
}
}
device->drop();
return 0;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
pd.- My intention is to develop a multiplatform and multiengine (Irrlicht and Ogre) video library

Posted: Tue Mar 13, 2007 10:10 pm
by monkeycracks
Could you include a movie file(doesn't have to be big) and a binary? I'll test it with my ATI Radeon 9650 if you want, but I don't have time to code+compile+get a movie file

Posted: Wed Mar 14, 2007 1:15 pm
by hansel
monkeycracks wrote:Could you include a movie file(doesn't have to be big) and a binary? I'll test it with my ATI Radeon 9650 if you want, but I don't have time to code+compile+get a movie file

Sorry but in this PC I only have 2 movies, one is private and the other is too large (120 Mb)
I have added new functions: pause, goToFrame, goToSecond, stop, restart, getFrameRate, getVideoTexture and setLoop.
videoPlayer.h
Code: Select all
#ifndef __VIDEO_PLAYER_H__
#define __VIDEO_PLAYER_H__
// irrlicht includes
#include "irrlicht.h"
// ffmpeg includes
#include <ffmpeg/avcodec.h>
#include <ffmpeg/avformat.h>
using namespace irr;
class cVideoPlayer
{
private:
irr::ITimer *Timer;
irr::video::IVideoDriver *IrrVideoDriver;
irr::video::IImage *CurrentImage;
irr::video::ITexture *CurrentTexture;
unsigned long lastTime;
double SecondsPerFrame;
AVFormatContext *FormatCtx;
int VideoStream;
AVCodecContext *CodecCtx;
AVCodec *Codec;
AVFrame *Frame;
AVFrame *FrameRGB;
int NumBytes;
uint8_t *Buffer;
bool GetNextFrame(AVFormatContext *pFormatCtx,
AVCodecContext *pCodecCtx,
int videoStream,
AVFrame *pFrame);
bool DumpFrame(AVFrame *pFrame, int width, int height);
s32* p;
s32* pimage;
enum cState {playing, paused, stopped, manual};
cState state;
bool streamOpen;
char* actualFilename;
int actualFrame;
bool loop;
int replayCont;
float framerate;
int seekFactor;
public:
// constructors
cVideoPlayer(irr::video::IVideoDriver *irrVideoDriver,
irr::ITimer *timer);
cVideoPlayer(irr::video::IVideoDriver *irrVideoDriver,
irr::ITimer *timer, char* filename);
// destructor
~cVideoPlayer();
// functions to open, play, and stop the media
bool open(char *filename);
// refresh the video
bool refresh();
// play the video
bool play();
// stop the video
bool stop();
// pause the video
bool pause();
// get the video texture
irr::video::ITexture* getVideoTexture();
// draw the video texture
void drawVideoTexture();
// close the video stream
bool restartStream();
// set looped
void setLoop(bool l);
// go to selected second
void goToSecond(int numSecond);
// get selected frame
bool goToFrame(int numFrame);
// get the movie framerate
float getFrameRate();
// get the seek factor (15 by default)
int getSeekFactor();
// set the seek factor
void setSeekFactor(int sf);
};
#endif
videoPlayer.cpp
Code: Select all
#include "videoPlayer.h"
#include <ffmpeg/avcodec.h>
#include <ffmpeg/avformat.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
// Original code by: juliusctw
// Modified by Hansel
// compile with:
// windows:
// g++ -o player cVideoPlayer.cpp -lavformat -lavcodec -lavutil -lz -I/c/code/iamar/irrlicht-1.2/include/ -L/c/code/iamar/irrlicht-1.2/bin/Win32-gcc/ -lIrrlicht
//
// linux:
// g++ -o player cVideoPlayer.cpp -lavformat -lavcodec -lavutil -lz -I../irrlicht/include/ -L../irrlicht -lIrrlicht -lGL -lGLU -lXxf86vm -lXext -lX11
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
cVideoPlayer::cVideoPlayer(irr::video::IVideoDriver *irrVideoDriver, irr::ITimer *timer)
: IrrVideoDriver(irrVideoDriver), Timer(timer)
{
IrrVideoDriver->setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);
IrrVideoDriver->setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true);
// Register all formats and codecs
av_register_all();
state = stopped;
streamOpen = false;
actualFrame = 0;
loop = false;
replayCont = 0;
seekFactor = 15;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
cVideoPlayer::cVideoPlayer(irr::video::IVideoDriver *irrVideoDriver, irr::ITimer *timer, char* filename)
: IrrVideoDriver(irrVideoDriver), Timer(timer)
{
IrrVideoDriver->setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);
IrrVideoDriver->setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true);
// Register all formats and codecs
av_register_all();
if (! open(filename))
{
printf("problem opening movie");
exit(1);
}
state = stopped;
streamOpen = false;
actualFrame = 0;
loop = false;
replayCont = 0;
seekFactor = 15;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
cVideoPlayer::~cVideoPlayer()
{
// Free the RGB image
if (Buffer != NULL)
delete [] Buffer;
if (FrameRGB != NULL)
av_free(FrameRGB);
// Free the YUV frame
if (Frame != NULL)
av_free(Frame);
// Close the codec
if (CodecCtx != NULL)
avcodec_close(CodecCtx);
// Close the video file
if (FormatCtx != NULL)
av_close_input_file(FormatCtx);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::open(char *filename)
{
actualFilename = filename;
// Open video file
if (av_open_input_file(&FormatCtx, filename, NULL, 0, NULL)!=0)
return false; // Couldn't open file
// Retrieve stream information
if (av_find_stream_info(FormatCtx)<0)
return false; // Couldn't find stream information
// Dump information about file onto standard error
dump_format(FormatCtx, 0, filename, false);
// Find the first video stream
VideoStream=-1;
for (int i=0; i<FormatCtx->nb_streams; i++)
if (FormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)
{
VideoStream=i;
break;
}
if (VideoStream==-1)
return false; // Didn't find a video stream
// Get a pointer to the codec context for the video stream
CodecCtx=FormatCtx->streams[VideoStream]->codec;
// Get the seconds/frame of this video stream
SecondsPerFrame = (double)FormatCtx->streams[VideoStream]->r_frame_rate.den / FormatCtx->streams[VideoStream]->r_frame_rate.num;
printf("Duration: %f", (double)FormatCtx->duration);
printf(" seconds per frame: %f\n", SecondsPerFrame);
// Find the decoder for the video stream
Codec=avcodec_find_decoder(CodecCtx->codec_id);
if (Codec==NULL)
return false; // Codec not found
// Inform the codec that we can handle truncated bitstreams -- i.e.,
// bitstreams where frame boundaries can fall in the middle of packets
if (Codec->capabilities & CODEC_CAP_TRUNCATED)
CodecCtx->flags|=CODEC_FLAG_TRUNCATED;
// Open codec
if (avcodec_open(CodecCtx, Codec)<0)
return false; // Could not open codec
// Allocate video frame
Frame=avcodec_alloc_frame();
// Allocate an AVFrame structure
FrameRGB=avcodec_alloc_frame();
if (FrameRGB==NULL)
return false;
// Determine required buffer size and allocate buffer
NumBytes=avpicture_get_size(PIX_FMT_RGB32,
CodecCtx->width,
CodecCtx->height);
Buffer=new uint8_t[NumBytes];
// Assign appropriate parts of buffer to image planes in pFrameRGB
avpicture_fill((AVPicture *)FrameRGB, Buffer, PIX_FMT_RGB32,
CodecCtx->width, CodecCtx->height);
// get the movie framerate
framerate = FormatCtx->streams[VideoStream]->r_frame_rate.num;
return true;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::refresh()
{
if (state == playing)
{
if (Timer->getRealTime() - lastTime > (SecondsPerFrame*1000))
{
if (GetNextFrame(FormatCtx, CodecCtx, VideoStream, Frame))
{
img_convert((AVPicture *)FrameRGB, PIX_FMT_RGB32, (AVPicture*)Frame,
CodecCtx->pix_fmt, CodecCtx->width, CodecCtx->height);
printf("Replay Num.: %d :: Dumping Frame: %d :: FrameRate: %f\n", replayCont, actualFrame, framerate);
// Dump the frame
DumpFrame(FrameRGB, CodecCtx->width, CodecCtx->height);
actualFrame++;
}
else
{
state = stopped;
printf("->End\n");
}
lastTime = Timer->getRealTime();
}
}
if (state == stopped)
{
actualFrame = 0;
restartStream();
// if looped then replay the movie
if (loop)
{
replayCont ++;
state = playing;
streamOpen = true;
}
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::play()
{
if (state == stopped) replayCont++;
state = playing;
streamOpen = true;
return true;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::stop()
{
state = stopped;
return true;
};
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::pause()
{
state = paused;
return true;
};
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::GetNextFrame(AVFormatContext *pFormatCtx,
AVCodecContext *pCodecCtx,
int videoStream,
AVFrame *pFrame)
{
static AVPacket packet;
static int bytesRemaining=0;
static uint8_t *rawData;
static bool fFirstTime=true;
int bytesDecoded;
int frameFinished;
// First time we're called, set packet.data to NULL to indicate it
// doesn't have to be freed
if (fFirstTime)
{
fFirstTime=false;
packet.data=NULL;
}
// Decode packets until we have decoded a complete frame
while (true)
{
// Work on the current packet until we have decoded all of it
while (bytesRemaining > 0)
{
// Decode the next chunk of data
bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame,
&frameFinished, rawData, bytesRemaining);
// Was there an error?
if (bytesDecoded < 0)
{
fprintf(stderr, "Error while decoding frame\n");
return false;
}
bytesRemaining-=bytesDecoded;
rawData+=bytesDecoded;
// Did we finish the current frame? Then we can return
if (frameFinished)
return true;
}
// Read the next packet, skipping all packets that aren't for this
// stream
do
{
// Free old packet
if (packet.data!=NULL)
av_free_packet(&packet);
// Read new packet
if (av_read_packet(pFormatCtx, &packet)<0)
goto loop_exit;
}
while (packet.stream_index!=videoStream);
bytesRemaining=packet.size;
rawData=packet.data;
}
loop_exit:
// Decode the rest of the last frame
bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,
rawData, bytesRemaining);
// Free last packet
if (packet.data!=NULL)
av_free_packet(&packet);
return frameFinished!=0;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::DumpFrame(AVFrame *pFrame,
int width,
int height)
{
static char first_time = 1;
if (first_time)
{
CurrentImage = IrrVideoDriver->createImageFromData(irr::video::ECF_A8R8G8B8,
irr::core::dimension2d<irr::s32>(width, height),
pFrame->data[0],
true);
first_time = 0;
CurrentTexture = IrrVideoDriver->addTexture("movie", CurrentImage);
}
p = (s32*)CurrentTexture->lock ();
pimage = (s32*)CurrentImage->lock ();
for (int i = 0; i < width*height; i++) p[i] = pimage[i];
// unlock de texture and the image
CurrentTexture->unlock();
CurrentImage->unlock();
return true;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
irr::video::ITexture* cVideoPlayer::getVideoTexture()
{
return CurrentTexture;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
void cVideoPlayer::drawVideoTexture()
{
// draw the texture
IrrVideoDriver->draw2DImage(CurrentTexture, irr::core::position2d<irr::s32>(0,0),
irr::core::rect<irr::s32>(0,0,1024,768), 0, irr::video::SColor(255,255,255,255), true);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::restartStream()
{
//Close stream
if ( FormatCtx && streamOpen)
{
streamOpen = false;
if (av_open_input_file(&FormatCtx, actualFilename, NULL, 0, NULL)!=0) return false; // Couldn't open file
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
void cVideoPlayer::setLoop(bool l)
{
loop = l;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
void cVideoPlayer::goToSecond(int numSecond)
{
restartStream();
state = manual;
goToFrame((int)framerate*numSecond);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
bool cVideoPlayer::goToFrame(int numFrame)
{
// seek the movie
if (numFrame < seekFactor) av_seek_frame(FormatCtx, VideoStream, numFrame, AVSEEK_FLAG_ANY);
else
{
av_seek_frame(FormatCtx, VideoStream, numFrame-seekFactor, AVSEEK_FLAG_ANY);
// advance to the real selected frame
for (int i = 0; i < seekFactor; i++) GetNextFrame(FormatCtx, CodecCtx, VideoStream, Frame);
}
actualFrame = numFrame;
printf("Replay Num.: %d :: Dumping Frame: %d :: FrameRate: %f\n", replayCont, actualFrame, framerate);
return true;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
float cVideoPlayer::getFrameRate()
{
return framerate;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
main.cpp
Code: Select all
#include "videoPlayer.h"
#include <stdio.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
using namespace irr;
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
IrrlichtDevice *device;
IVideoDriver* driver;
ISceneManager* smgr;
cVideoPlayer* videoPlayer;
class MyEventReceiver : public IEventReceiver
{
public:
virtual bool OnEvent(SEvent event)
{
/*
If the key 'W' or 'S' was left up, we get the position of the scene node,
and modify the Y coordinate a little bit. So if you press 'W', the node
moves up, and if you press 'S' it moves down.
*/
if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case KEY_KEY_A: videoPlayer->play();
printf("-> Play\n");
break;
case KEY_KEY_S: videoPlayer->pause();
printf("-> Pause\n");
break;
case KEY_KEY_D: videoPlayer->stop();
printf("-> Stop\n");
break;
return true;
case KEY_KEY_F: videoPlayer->goToSecond(20);
printf("-> Manual\n");
break;
return true;
}
}
return false;
}
};
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
MyEventReceiver receiver;
device = createDevice( video::EDT_OPENGL, dimension2d<s32>(640, 480), 32, false, false, false, &receiver);
driver = device->getVideoDriver();
smgr = device->getSceneManager();
// initialise the videoPlayer with a filename
videoPlayer = new cVideoPlayer(driver, device->getTimer(), "Futurama.avi");
videoPlayer->setLoop(false);
// to get the framerate (fps)
int lastFPS = -1;
while (device->run())
{
static int i = 0;
driver->beginScene(true, true, SColor(255,100,101,140));
// refresh the video
videoPlayer->refresh();
// draw the texture in a rectangle
videoPlayer->drawVideoTexture();
//smgr->drawAll();
driver->endScene();
// show the framerate (fps)
int fps = driver->getFPS();
if (lastFPS != fps)
{
wchar_t tmp[1024];
swprintf(tmp, 1024, L"Video Example - Irrlicht Engine [%ls] fps: %d",
driver->getName(), fps);
device->setWindowCaption(tmp);
lastFPS = fps;
}
}
device->drop();
return 0;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------
