Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

ffmpeg support

  • Loading branch information...
commit 2f725ecc14a1aa20bad877f45a980d27f1178374 1 parent 0d347ed
Stefan Sydow authored
Showing with 206 additions and 12 deletions.
  1. +5 −0 configure.ac
  2. +34 −1 src/main.cpp
  3. +1 −0  src/main.h
  4. +126 −10 src/ppm.cpp
  5. +40 −1 src/ppm.h
View
5 configure.ac
@@ -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))
View
35 src/main.cpp
@@ -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);
@@ -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()) {
@@ -442,6 +462,19 @@ int main(int argc, char *argv[]) {
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);
+ }
}
if(multisample) glEnable(GL_MULTISAMPLE_ARB);
@@ -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);
}
View
1  src/main.h
@@ -20,6 +20,7 @@
#include <vector>
#include <string>
+#include <X11/Xlib.h>
#include "logstalgia.h"
View
136 src/ppm.cpp
@@ -16,6 +16,8 @@
*/
#include "ppm.h"
+#include <assert.h>
+
extern "C" {
static int dumper_thread(void *arg) {
@@ -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;
@@ -74,7 +75,6 @@ FrameExporter::~FrameExporter() {
delete[] pixels1;
delete[] pixels2;
- delete[] pixels_out;
}
void FrameExporter::dump() {
@@ -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;
@@ -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() {
@@ -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);
+
+}
View
41 src/ppm.h
@@ -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 };
@@ -36,7 +48,6 @@ class FrameExporter {
char* pixels1;
char* pixels2;
- char* pixels_out;
char* pixels_shared_ptr;
@@ -72,6 +83,7 @@ class PPMExporter : public FrameExporter {
std::ostream* output;
std::string filename;
char ppmheader[1024];
+ char* pixels_out;
public:
PPMExporter(std::string outputfile);
@@ -79,5 +91,32 @@ class PPMExporter : public FrameExporter {
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
Please sign in to comment.
Something went wrong with that request. Please try again.