Playing movie in texture
didn't turn off mipmap
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
I think i forgot this ,
driver->setTextureCreationFlag(ETCF_ALWAYS_32_BIT, false );
i'll give this a try and let you guys know
irrlicht game character project
http://picasaweb.google.com/juliusctw/FinishedArt
http://picasaweb.google.com/juliusctw/FinishedArt
Here my code and my problem
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
Here is the header file
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
irrlicht game character project
http://picasaweb.google.com/juliusctw/FinishedArt
http://picasaweb.google.com/juliusctw/FinishedArt
finally profiled the problem
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?
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?
irrlicht game character project
http://picasaweb.google.com/juliusctw/FinishedArt
http://picasaweb.google.com/juliusctw/FinishedArt
alright i'll do that
alright, i'll give that a try and report back when i'm done , thanks
irrlicht game character project
http://picasaweb.google.com/juliusctw/FinishedArt
http://picasaweb.google.com/juliusctw/FinishedArt
i did it
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?
irrlicht game character project
http://picasaweb.google.com/juliusctw/FinishedArt
http://picasaweb.google.com/juliusctw/FinishedArt
ok, i got it
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
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
irrlicht game character project
http://picasaweb.google.com/juliusctw/FinishedArt
http://picasaweb.google.com/juliusctw/FinishedArt
i am so stuck
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?
everything seems fine, but some times, the libav load frame function won't read the entire frame? anybody?
irrlicht game character project
http://picasaweb.google.com/juliusctw/FinishedArt
http://picasaweb.google.com/juliusctw/FinishedArt
It all works now
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.
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.
irrlicht game character project
http://picasaweb.google.com/juliusctw/FinishedArt
http://picasaweb.google.com/juliusctw/FinishedArt
-
- Posts: 518
- Joined: Tue Mar 29, 2005 9:02 pm
- Location: Alex,Egypt
- Contact:
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.
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.
Magic 2d Library For Irrlicht : http://www.freewebs.com/bcxgl/index.htm
http://www.freewebs.com/bcxdx/index.htm
http://groups.yahoo.com/group/bcxdxc/
http://www.freewebs.com/bcxdx/index.htm
http://groups.yahoo.com/group/bcxdxc/
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
videoPlayer.cpp
main.cpp
pd.- My intention is to develop a multiplatform and multiengine (Irrlicht and Ogre) video library
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
-
- Posts: 1029
- Joined: Thu Apr 06, 2006 12:45 am
- Location: Tennesee, USA
- Contact:
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;
}
//-----------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------