Skip to content

Commit

Permalink
ffmpeg support
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Sydow committed Oct 11, 2011
1 parent 0d347ed commit 2f725ec
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 12 deletions.
5 changes: 5 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ AC_CHECK_LIB(SDL_image, IMG_LoadPNG_RW, LIBS="$LIBS -lSDL_image", AC_MSG_ERROR([
#PCRE
AC_CHECK_LIB([pcre], [pcre_compile],, AC_MSG_ERROR(PCRE is required. Please see INSTALL))

#ffmpeg library
AC_CHECK_LIB(avformat, avcodec_encode_video, LIBS="$LIBS -lavformat", AC_MSG_ERROR([ffmpeg library required. Please see INSTALL]))
AC_CHECK_LIB(avcodec, avcodec_encode_video, LIBS="$LIBS -lavcodec", AC_MSG_ERROR([ffmpeg library required. Please see INSTALL]))
AC_CHECK_LIB(swscale, sws_scale, LIBS="$LIBS -lswscale", AC_MSG_ERROR([ffmpeg library required. Please see INSTALL]))

#Check for required headers
AC_CHECK_HEADER([SDL.h],, AC_MSG_ERROR(SDL.h is required. Please see INSTALL))
AC_CHECK_HEADER([SDL_image.h],, AC_MSG_ERROR(SDL_image.h is required. Please see INSTALL))
Expand Down
35 changes: 34 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,15 @@ int main(int argc, char *argv[]) {
int video_framerate = 60;
std::string ppm_file_name;

std::string mpeg_file_name;

std::string logfile = "";

std::vector<std::string> groupstr;

std::vector<std::string> arguments;

XInitThreads();
SDLAppInit("Logstalgia", "logstalgia");

SDLAppParseArgs(argc, argv, &width, &height, &fullscreen, &arguments);
Expand Down Expand Up @@ -355,6 +358,23 @@ int main(int argc, char *argv[]) {
continue;
}

if(args == "--output-mpeg-stream") {

if((i+1)>=arguments.size()) {
logstalgia_quit("specify mpeg output file or '-' for stdout");
}

mpeg_file_name = arguments[++i];

#ifdef _WIN32
if(mpeg_file_name == "-") {
logstalgia_quit("stdout MPEG mode not supported on Windows");
}
#endif

continue;
}

if(args == "--output-framerate") {

if((i+1)>=arguments.size()) {
Expand Down Expand Up @@ -440,6 +460,19 @@ int main(int argc, char *argv[]) {
char errormsg[1024];
snprintf(errormsg, 1024, "could not write to '%s'", exception.what());

logstalgia_quit(errormsg);
}
}else if(mpeg_file_name.size() > 0) {

try {

exporter = new MPEGExporter(mpeg_file_name);

} catch(MPEGExporterException& exception) {

char errormsg[1024];
snprintf(errormsg, 1024, "could not write to '%s'", exception.what());

logstalgia_quit(errormsg);
}
}
Expand All @@ -452,7 +485,7 @@ int main(int argc, char *argv[]) {
ls = new Logstalgia(logfile, simu_speed, update_rate, time_scale);

//init frame exporter
if(ppm_file_name.size() > 0) {
if(ppm_file_name.size() > 0 || mpeg_file_name.size() > 0) {
ls->setFrameExporter(exporter, video_framerate);
}

Expand Down
1 change: 1 addition & 0 deletions src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <vector>
#include <string>
#include <X11/Xlib.h>

#include "logstalgia.h"

Expand Down
136 changes: 126 additions & 10 deletions src/ppm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/

#include "ppm.h"
#include <assert.h>


extern "C" {
static int dumper_thread(void *arg) {
Expand All @@ -39,7 +41,6 @@ FrameExporter::FrameExporter() {

pixels1 = new char[display.height * rowstride];
pixels2 = new char[display.height * rowstride];
pixels_out = new char[display.height * rowstride];

pixels_shared_ptr = 0;

Expand Down Expand Up @@ -74,7 +75,6 @@ FrameExporter::~FrameExporter() {

delete[] pixels1;
delete[] pixels2;
delete[] pixels_out;
}

void FrameExporter::dump() {
Expand Down Expand Up @@ -112,15 +112,8 @@ void FrameExporter::dumpThr() {
if (dumper_thread_state == FRAME_EXPORTER_EXIT) break;

if (pixels_shared_ptr != 0) {

//invert image
for(int y=0;y<display.height;y++) {
for(int x=0;x<rowstride;x++) {
pixels_out[x + y * rowstride] = pixels_shared_ptr[x + (display.height - y - 1) * rowstride];
}
}

dumpImpl();

}

dumper_thread_state = FRAME_EXPORTER_WAIT;
Expand Down Expand Up @@ -151,6 +144,8 @@ PPMExporter::PPMExporter(std::string outputfile) {
sprintf(ppmheader, "P6\n# Generated by %s\n%d %d\n255\n",
gSDLAppTitle.c_str(), display.width, display.height
);

pixels_out = new char[display.height * rowstride];
}

PPMExporter::~PPMExporter() {
Expand All @@ -161,12 +156,133 @@ PPMExporter::~PPMExporter() {
SDL_CondSignal(cond);

SDL_mutexV(mutex);
delete[] pixels_out;

if(filename.size()>0)
((std::fstream*)output)->close();
}

void PPMExporter::dumpImpl() {
int y_dst, y_src;
*output << ppmheader;
//invert image
for(int y=0;y<display.height;y++) {
y_dst = y * rowstride;
y_src = (display.height - y - 1) * rowstride;
memcpy(pixels_out + y_dst,pixels_shared_ptr + y_src, rowstride* sizeof(char));
}
output->write(pixels_out, rowstride * display.height);
}

// MPEGExporter

MPEGExporter::MPEGExporter(std::string outputfile):
out_size(0), c(NULL)
{

avcodec_init();
avcodec_register_all();


if(outputfile == "-") {
output = &std::cout;

} else {
filename = outputfile;
output = new std::ofstream(outputfile.c_str(), std::ios::out | std::ios::binary);

if(output->fail()) {
std::string msg = "can't open outfile \"";
msg += outputfile;
msg += "\"";
delete output;
throw MPEGExporterException(msg);
}
}

codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO);
if (!codec) {
delete output;
throw MPEGExporterException("codec not found");
}

c = avcodec_alloc_context3(codec);
picture= avcodec_alloc_frame();
picture_yuv= avcodec_alloc_frame();

/* put sample parameters */
c->bit_rate = 400000;
assert(display.width % 2 == 0);
assert(display.height % 2 == 0);
c->width = display.width;
c->height = display.height;
/* frames per second */
c->time_base= (AVRational){1,25};
c->gop_size = 10; /* emit one intra frame every ten frames */
c->max_b_frames=1;
c->pix_fmt = PIX_FMT_YUV420P;

/* open it */
if (avcodec_open(c, codec) < 0) {
delete output;
throw MPEGExporterException("could not open codec");
}
img_convert_ctx = sws_getContext(
display.width, display.height, PIX_FMT_RGB24,
display.width, display.height, PIX_FMT_YUV420P,
SWS_CPU_CAPS_MMX|SWS_CPU_CAPS_MMX2|SWS_CPU_CAPS_3DNOW|
SWS_FAST_BILINEAR,
NULL, NULL, NULL);
outbuf = (uint8_t*)malloc(MPEG_BUF_SIZE);

printf("%d, %d\n", c->width, c->height);
avpicture_alloc((AVPicture *)picture, PIX_FMT_RGB24, c->width, c->height);
avpicture_alloc((AVPicture *)picture_yuv, PIX_FMT_YUV420P, c->width, c->height);
}

MPEGExporter::~MPEGExporter() {

SDL_mutexP(mutex);

dumper_thread_state = FRAME_EXPORTER_EXIT;

SDL_CondSignal(cond);

SDL_mutexV(mutex);

while(out_size){
out_size = avcodec_encode_video(c, outbuf, MPEG_BUF_SIZE, NULL);
output->write((char*)outbuf, out_size);
}

avcodec_close(c);
av_free(c);
av_free(picture->data[0]);
av_free(picture_yuv->data[0]);
av_free(picture);
av_free(picture_yuv);

if(filename.size()>0){
outbuf[0] = 0x00;
outbuf[1] = 0x00;
outbuf[2] = 0x01;
outbuf[3] = 0xb7;
output->write((char*)outbuf, 4);
((std::fstream*)output)->close();
}
free(outbuf);
}

void MPEGExporter::dumpImpl() {
uint8_t *data = picture->data[0];
int y_src, y_dst;
for(int y=0;y<display.height;y++) {
y_dst = y * rowstride;
y_src = (display.height - y - 1) * rowstride;
memcpy(data + y_dst,pixels_shared_ptr + y_src, rowstride* sizeof(char));
}
sws_scale(img_convert_ctx, picture->data, picture->linesize, 0, c->height, picture_yuv->data, picture_yuv->linesize);
out_size = avcodec_encode_video(c, outbuf, MPEG_BUF_SIZE, picture_yuv);
output->write((char*)outbuf, out_size);

}
41 changes: 40 additions & 1 deletion src/ppm.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,21 @@

#include "SDL_thread.h"

#ifndef INT64_C
#define INT64_C(c) (c ## LL)
#define UINT64_C(c) (c ## ULL)
#endif

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/mathematics.h>
#include <libswscale/swscale.h>
}

#include "core/sdlapp.h"
#include "core/display.h"

#define MPEG_BUF_SIZE 100000
enum { FRAME_EXPORTER_WAIT,
FRAME_EXPORTER_DUMP,
FRAME_EXPORTER_EXIT };
Expand All @@ -36,7 +48,6 @@ class FrameExporter {

char* pixels1;
char* pixels2;
char* pixels_out;

char* pixels_shared_ptr;

Expand Down Expand Up @@ -72,12 +83,40 @@ class PPMExporter : public FrameExporter {
std::ostream* output;
std::string filename;
char ppmheader[1024];
char* pixels_out;

public:
PPMExporter(std::string outputfile);
virtual ~PPMExporter();
virtual void dumpImpl();
};

class MPEGExporterException : public std::exception {
protected:
const char* cause;
public:
MPEGExporterException(const char* cause) : cause(cause) {}
MPEGExporterException(std::string& cause) : cause(cause.c_str()) {}
virtual ~MPEGExporterException() throw () {};

virtual const char* what() const throw() { return cause; }
};

class MPEGExporter : public FrameExporter {
protected:
std::ostream* output;
std::string filename;
AVCodec *codec;
AVCodecContext *c, *c_yuv;
AVFrame *picture_yuv, *picture;
SwsContext *img_convert_ctx;
uint8_t *outbuf;
int out_size;

public:
MPEGExporter(std::string outputfile);
virtual ~MPEGExporter();
virtual void dumpImpl();
};

#endif

0 comments on commit 2f725ec

Please sign in to comment.