• Advertisement
Sign in to follow this  

Playing Back Video with SDL

This topic is 4478 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello! I was wondering if SDL can play back video files somehow. I'm sure it can, especially since it's used to create media players on non-Windows platforms, but... how? Would I be able to play back an Indio or DivX encoded movie file? I'd like to be able to play back a video and draw over it. Is this possible? What do I need? All help is appreciated! :-)

Share this post


Link to post
Share on other sites
Advertisement
Sure, you can pull it off using ffmpeg, the source comes with an SDL sample which is rather complex, but if you google for some examples, you should be able to find code to just play the video.

I currently use it to play videos on OpenGL textures.

Share this post


Link to post
Share on other sites
I'm confused.

I downloaded the only available official release of ffmpeg and got a huge jumble of source files. I don't know how to build a library out of any of this and it seems to be an application for converting audio and video content rather than a library.

So... how do I use this? Haha, sorry for my incompetence. :-)

Share this post


Link to post
Share on other sites
Quote:
Original post by eviltwigflipper
I can't remember the link off hand, but you could use the SDL example for loading ROQ(Quake and Doom 3 movie files), the implementation was rather simple.


Very interesting! I did a little searching and it seems you can get a plugin for ffmpeg to make those files, as well as some other stuff. I will look into this myself later on when time permits, thanks for sharing! One question though, what is the license of that format? If it is propierty, then it'd be better not to use it in your games, which also I should add, SMPEG is GPL, so you have to release all source if you want to use it. Just something to keep in mind as well.

Share this post


Link to post
Share on other sites
Well, with ffmpeg you have to compile from sources before using it, they recomend always grabbing the latest code from CVS, I use rpms for Linux and compile using MinGW and MSYS on Windows, its not that hard once you figure out which parameters to pass to configure.

What you need are the 3 AV libraries (avcodec.dll,avformat.dll and avutil.dll) build and then link them to your program.

Basically what you do is grab a stream from the video file (which may be Video, Sound or Subtitles) and in the case of the video one, start decoding frames, rendering them to SDL surfaces and then blit them to the screen.

You do HAVE to be very careful about what format you use, MPEG is pattent encumbered, and so is DivX, I really recomend theora, which uses the same philosophy as Vorbis does for audio (in fact it uses Vorbis for audio streams).

ffmpeg can handle theora.

Here is a link I found when writting my video to texture code, and here is my code based on that, sorry for the sloppiness and the mess, I focused on getting something working I could go back and carefully work out better later:

// (c) 2005 Rodrigo Hernandez
#ifndef VIDEO_H
#define VIDEO_H
#include <ffmpeg/avcodec.h>
#include <ffmpeg/avformat.h>
#include <string>
#include "SDL.h"
#include "SDL_thread.h"
#include "SDL_opengl.h"
class Video
{
public:
Video();
~Video();
bool Load(const char*);
void Play();
void Stop();
void Pause();
void Update(); // Called every frame or so to advance playing
inline GLuint GetTexture(){return videotex;};
inline unsigned int GetTexWidth() {return width;};
inline unsigned int GetTexHeight(){return height;};
inline unsigned int GetVidWidth() {return pCodecCtx->width;};
inline unsigned int GetVidHeight(){return pCodecCtx->height;};
private:
/* static int video_thread(void *); */
static int audio_thread(void *);
std::string filename;
bool ispaused;
bool stop;
GLuint videotex;
// SDL_Thread *vid_thread;
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame;
AVFrame *pFrameRGB;
int videoStream;
uint8_t *buffer;
int numBytes;
AVPacket packet;
unsigned int width;
unsigned int height;
Uint32 time_between_frames;
Uint32 ticks;
};

#endif






// (c) 2005 Rodrigo Hernandez
#include <assert.h>
#include "video.h"

inline void FindBestTextureSize(unsigned int &w,unsigned int &h)
{
Uint32 temp = 1;
while(w>temp)
{
temp = temp << 1;
}
if(w==h)
{
w=h=temp;
return;
}
w=temp;
temp = 1;
while(h>temp)
{
temp = temp << 1;
}
h=temp;
}

Video::Video()
{
ispaused=false;
stop=false;
videotex=0;
pFormatCtx=NULL;
//vid_thread=NULL;
buffer=NULL;
}
Video::~Video()
{
//SDL_WaitThread(vid_thread,NULL);
stop=true;
// Free the RGB image
if(buffer!=NULL) delete [] buffer;
av_free(pFrameRGB);
// Free the YUV frame
av_free(pFrame);
// Close the codec
avcodec_close(pCodecCtx);
// Close the video file
if(pFormatCtx!=NULL)
{
// Close the video file
av_close_input_file(pFormatCtx);
}
if(videotex!=0)
{
glDeleteTextures(1,&videotex);
}
}
bool Video::Load(const char* videofile)
{
GLenum error;
//filename=videofile;
// this should probably be moved somewhere else
av_register_all();
// Open video file
if(av_open_input_file(&pFormatCtx, videofile, NULL, 0, NULL)!=0)
{
fprintf(stderr,"Couldn't open file %s\n",videofile);
return false; // Couldn't open file
}
// Retrieve stream information
if(av_find_stream_info(pFormatCtx)<0)
{
fprintf(stderr,"Couldn't find stream information in %s\n",videofile);
return false; // Couldn't find stream information
}
// Dump information about file onto standard error
dump_format(pFormatCtx, 0, videofile, false);

// Create Texture for rendering the Video
glGenTextures(1, &videotex);
fprintf(stderr,"Tex Name %u\n",videotex);
if((error=glGetError())!=GL_NO_ERROR)
{
fprintf(stderr,"OpenGL Error %d in Load\n",error);
}
glBindTexture(GL_TEXTURE_2D,videotex);
if((error=glGetError())!=GL_NO_ERROR)
{
if(error==GL_INVALID_ENUM)
{
fprintf(stderr,"glBindTexture OpenGL Error GL_INVALID_ENUM Tex Name %u\n",videotex);
}
else if(error==GL_INVALID_OPERATION)
{
fprintf(stderr,"glBindTexture OpenGL Error GL_INVALID_OPERATION Tex Name %u\n",videotex);
}
}

// Find the first video stream
videoStream=-1;
for(int i=0; i<pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams->codec->codec_type==CODEC_TYPE_VIDEO)
{
videoStream=i;
break;
}
}
if(videoStream==-1)
{
fprintf(stderr,"No video stream\n");
return false; // Didn't find a video stream
}
// Get a pointer to the codec context for the video stream
pCodecCtx=pFormatCtx->streams[videoStream]->codec;

// Find the decoder for the video stream
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==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(pCodec->capabilities & CODEC_CAP_TRUNCATED)
pCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
// Open codec
if(avcodec_open(pCodecCtx, pCodec)<0)
return false; // Could not open codec

// Allocate video frame
pFrame=avcodec_alloc_frame();

// Allocate an AVFrame structure
pFrameRGB=avcodec_alloc_frame();
if(pFrameRGB==NULL)
return false;

// Determine required buffer size and allocate buffer
numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
pCodecCtx->height);
buffer=new uint8_t[numBytes];

// Assign appropriate parts of buffer to image planes in pFrameRGB
avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
pCodecCtx->width, pCodecCtx->height);
time_between_frames=int(av_q2d(pCodecCtx->time_base)*1000);
fprintf(stderr,"%d/%d TBF %u\n",
pCodecCtx->time_base.num,
pCodecCtx->time_base.den,time_between_frames);
// Allocate OpenGL Texture
width =pCodecCtx->width;
height=pCodecCtx->height;
FindBestTextureSize(width,height);
fprintf(stderr,"Texture size %dx%d\n",width,height);

//unsigned char *data=new unsigned char[width*height*3];
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGB,
width,
height,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
NULL);
if((error=glGetError())!=GL_NO_ERROR)
{
fprintf(stderr,"glTexImage2D OpenGL Error %d\n",error);
}
//delete [] data;

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
if((error=glGetError())!=GL_NO_ERROR)
{
fprintf(stderr,"OpenGL Error\n");
}
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
if((error=glGetError())!=GL_NO_ERROR)
{
fprintf(stderr,"OpenGL Error\n");
}
return true;
}

void Video::Play()
{
ispaused=false;
stop=false;
}
void Video::Stop()
{
stop=true;
}

void Video::Pause()
{
if(ispaused)ispaused=false;
else ispaused=true;
}


void Video::Update()
{
GLenum error;
int frameFinished;
if(av_read_frame(pFormatCtx, &packet)>=0)
{
// Is this a packet from the video stream?
if(packet.stream_index==videoStream)
{
// Decode video frame
avcodec_decode_video(pCodecCtx,
pFrame, &frameFinished,
packet.data, packet.size);
// Did we get a video frame?
if(frameFinished)
{
// Convert the image from its native format to RGB
img_convert((AVPicture *)pFrameRGB,
PIX_FMT_RGB24,
(AVPicture*)pFrame,
pCodecCtx->pix_fmt,
pCodecCtx->width,
pCodecCtx->height);
// --- Add image to texture code here --- //
glBindTexture(GL_TEXTURE_2D,videotex);
glTexSubImage2D(GL_TEXTURE_2D,
0,
0,
0,
pCodecCtx->width,
pCodecCtx->height,
GL_RGB,
GL_UNSIGNED_BYTE,
pFrameRGB->data[0]);
if((error=glGetError())!=GL_NO_ERROR)
{
if(error==GL_INVALID_OPERATION)
{
fprintf(stderr,"glTexSubImage Error GL_INVALID_OPERATION\n");
}
else
{
fprintf(stderr,"glTexSubImage Error %d\n",error);
}
}
SDL_Delay(time_between_frames);
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
}
}

int Video::audio_thread(void *arg)
{
Video *v=(Video *)arg;
return 0;
}




Share this post


Link to post
Share on other sites
So it seems that I'd be able to use more formats with ffmpeg than with SMpeg, which apparently only plays back MPEG encoded files.

I'm already in the process of creating a small wrapper for SMpeg to see if I can get it up and working, but I'll see what I can make of the ffmpeg files I downloaded. It's still a bit confusing. :-P

Thanks for all of the help!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement