mirror of
https://github.com/NGSolve/netgen.git
synced 2024-12-24 21:10:33 +05:00
Update for new FFMPEG version, extra header for implementation
This commit is contained in:
parent
515e68260d
commit
74cb50d5ce
@ -126,6 +126,7 @@ set_vars( NETGEN_CMAKE_ARGS
|
||||
USE_CCACHE
|
||||
USE_NATIVE_ARCH
|
||||
USE_OCC
|
||||
USE_MPEG
|
||||
INSTALL_DIR
|
||||
INSTALL_DEPENDENCIES
|
||||
INTEL_MIC
|
||||
|
250
ng/encoding.hpp
Normal file
250
ng/encoding.hpp
Normal file
@ -0,0 +1,250 @@
|
||||
#ifndef ENCODING_HPP_INCLUDED__
|
||||
#define ENCODING_HPP_INCLUDED__
|
||||
|
||||
#ifdef FFMPEG
|
||||
|
||||
extern "C" {
|
||||
#include <libavutil/avassert.h>
|
||||
#include <libavutil/channel_layout.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/mathematics.h>
|
||||
#include <libavutil/timestamp.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libswresample/swresample.h>
|
||||
}
|
||||
|
||||
constexpr int BITRATE = 50000000;
|
||||
|
||||
class Mpeg {
|
||||
private:
|
||||
bool is_started =false;
|
||||
int framerate = 25;
|
||||
AVOutputFormat *fmt;
|
||||
AVFormatContext *oc;
|
||||
|
||||
AVStream *st;
|
||||
AVCodecContext *enc;
|
||||
|
||||
AVFrame *frame;
|
||||
AVFrame *rgb_frame;
|
||||
uint8_t *rgb_buffer;
|
||||
|
||||
struct SwsContext *sws_ctx;
|
||||
|
||||
AVFrame *alloc_picture(enum AVPixelFormat pix_fmt)
|
||||
{
|
||||
AVFrame *picture;
|
||||
|
||||
picture = av_frame_alloc();
|
||||
if (!picture)
|
||||
return NULL;
|
||||
|
||||
picture->format = pix_fmt;
|
||||
picture->width = width;
|
||||
picture->height = height;
|
||||
|
||||
av_frame_get_buffer(picture, 32);
|
||||
return picture;
|
||||
}
|
||||
|
||||
public:
|
||||
int width;
|
||||
int height;
|
||||
bool IsStarted() { return is_started; }
|
||||
int AddFrame() {
|
||||
int ret;
|
||||
int got_packet = 0;
|
||||
AVPacket pkt = { 0 };
|
||||
|
||||
glReadPixels (0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, rgb_buffer);
|
||||
av_image_fill_arrays(rgb_frame->data, rgb_frame->linesize, rgb_buffer, AV_PIX_FMT_RGB24, width, height, 1);
|
||||
|
||||
|
||||
if (av_frame_make_writable(frame) < 0)
|
||||
return 1;
|
||||
|
||||
// The picture is upside down - flip it:
|
||||
auto data = rgb_frame->data[0] + 3*width*height;
|
||||
uint8_t *flipped_data[4] = { data, data, data, data };
|
||||
int flipped_stride[4] = { -rgb_frame->linesize[0], -rgb_frame->linesize[1], -rgb_frame->linesize[2], -rgb_frame->linesize[3] };
|
||||
sws_scale(sws_ctx, flipped_data, flipped_stride, 0, enc->height, frame->data, frame->linesize);
|
||||
|
||||
|
||||
av_init_packet(&pkt);
|
||||
|
||||
got_packet = 0;
|
||||
ret = avcodec_send_frame(enc, frame);
|
||||
if (ret < 0)
|
||||
{
|
||||
cerr << "Error encoding video frame: " << endl;
|
||||
return(1);
|
||||
}
|
||||
|
||||
ret = avcodec_receive_packet(enc, &pkt);
|
||||
if (!ret)
|
||||
got_packet = 1;
|
||||
if (ret == AVERROR(EAGAIN))
|
||||
return 0;
|
||||
|
||||
if (ret < 0) {
|
||||
cerr << "Error encoding video frame: " << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (got_packet) {
|
||||
/* rescale output packet timestamp values from codec to stream timebase */
|
||||
av_packet_rescale_ts(&pkt, enc->time_base, st->time_base);
|
||||
pkt.stream_index = st->index;
|
||||
|
||||
/* Write the compressed frame to the media file. */
|
||||
ret = av_interleaved_write_frame(oc, &pkt);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
cerr << "Error while writing video frame: " << endl;
|
||||
return(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Start(string filename) {
|
||||
AVCodec *video_codec;
|
||||
if(is_started) {
|
||||
cerr << "Stream already started" << endl;
|
||||
return 1;
|
||||
}
|
||||
is_started = true;
|
||||
|
||||
GLint dims[4] = {0};
|
||||
glGetIntegerv(GL_VIEWPORT, dims);
|
||||
width = dims[2];
|
||||
height= dims[3];
|
||||
|
||||
width = int((width+1)/4)*4+4;
|
||||
height = 2 * (height/2);
|
||||
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
av_register_all();
|
||||
|
||||
avformat_alloc_output_context2(&oc, NULL, NULL, filename.c_str());
|
||||
// oc->preload= (int)(0.5*AV_TIME_BASE);
|
||||
oc->max_delay= (int)(0.7*AV_TIME_BASE);
|
||||
|
||||
fmt = oc->oformat;
|
||||
|
||||
if (fmt->video_codec != AV_CODEC_ID_NONE) {
|
||||
/* find the encoder */
|
||||
video_codec = avcodec_find_encoder(fmt->video_codec);
|
||||
if (!(video_codec)) {
|
||||
cerr << "Could not find encoder for '" << avcodec_get_name(fmt->video_codec) << "'" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
st = avformat_new_stream(oc, NULL);
|
||||
if (!st) {
|
||||
cerr << "Could not allocate stream\n";
|
||||
return 1;
|
||||
}
|
||||
st->id = oc->nb_streams-1;
|
||||
enc = avcodec_alloc_context3(video_codec);
|
||||
if (!enc) {
|
||||
cerr << "Could not alloc an encoding context\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
enc->codec_id = fmt->video_codec;
|
||||
|
||||
enc->bit_rate = BITRATE;
|
||||
enc->width = width;
|
||||
enc->height = height;
|
||||
st->time_base = (AVRational){ 1, framerate };
|
||||
enc->time_base = st->time_base;
|
||||
|
||||
enc->gop_size = 200;
|
||||
enc->pix_fmt = AV_PIX_FMT_YUV420P;
|
||||
if (enc->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
|
||||
enc->max_b_frames = 3;
|
||||
}
|
||||
if (enc->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
|
||||
enc->mb_decision = 2;
|
||||
}
|
||||
|
||||
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
|
||||
enc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||
|
||||
// enc->flags |= CODEC_FLAG_QSCALE;
|
||||
// enc->global_quality = 1180;
|
||||
}
|
||||
else {
|
||||
cerr << "could not init codecs!" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
AVDictionary *opt = NULL;
|
||||
|
||||
/* open the codec */
|
||||
ret = avcodec_open2(enc, video_codec, &opt);
|
||||
av_dict_free(&opt);
|
||||
if (ret < 0) {
|
||||
cerr << "Could not open video codec" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* allocate and init a re-usable frame */
|
||||
frame = alloc_picture(enc->pix_fmt);
|
||||
if (!frame) {
|
||||
cerr << "Could not allocate video frame\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* copy the stream parameters to the muxer */
|
||||
ret = avcodec_parameters_from_context(st->codecpar, enc);
|
||||
if (ret < 0) {
|
||||
cerr << "Could not copy the stream parameters\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
av_dump_format(oc, 0, filename.c_str(), 1);
|
||||
|
||||
if (!(fmt->flags & AVFMT_NOFILE)) {
|
||||
ret = avio_open(&oc->pb, filename.c_str(), AVIO_FLAG_WRITE);
|
||||
if (ret < 0) {
|
||||
cerr << "Could not open " << filename << " : " << endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
ret = avformat_write_header(oc, &opt);
|
||||
if (ret < 0) {
|
||||
cerr << "Error occurred when opening output file: " << endl;;
|
||||
return 1;
|
||||
}
|
||||
|
||||
rgb_frame = alloc_picture(AV_PIX_FMT_RGB24);
|
||||
rgb_buffer = new uint8_t[width*height*4];
|
||||
sws_ctx = sws_getContext( width, height, AV_PIX_FMT_RGB24,
|
||||
width, height, AV_PIX_FMT_YUV420P,
|
||||
SWS_BICUBIC, NULL, NULL, NULL );
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
av_write_trailer(oc);
|
||||
avcodec_free_context(&enc);
|
||||
av_frame_free(&frame);
|
||||
sws_freeContext(sws_ctx);
|
||||
if (!(fmt->flags & AVFMT_NOFILE))
|
||||
avio_closep(&oc->pb);
|
||||
avformat_free_context(oc);
|
||||
delete [] rgb_buffer;
|
||||
is_started = false;
|
||||
}
|
||||
};
|
||||
#endif // FFMPEG
|
||||
#endif // ENCODING_HPP_INCLUDED__
|
@ -319,7 +319,7 @@ proc demoredraw { } {
|
||||
global videoactive
|
||||
if { $videoactive == 1 } {
|
||||
puts "addframe"
|
||||
.ndraw Ng_VideoClip addframe
|
||||
Ng_VideoClip .ndraw addframe
|
||||
}
|
||||
if { $result == 0 && $stopdemo == 0 } {
|
||||
after 1 { demoredraw }
|
||||
@ -367,14 +367,14 @@ set videoactive 0
|
||||
}
|
||||
set file [tk_getSaveFile -filetypes $types]
|
||||
if {$file != ""} {
|
||||
.ndraw Ng_VideoClip init $file
|
||||
Ng_VideoClip .ndraw init $file
|
||||
global videoactive
|
||||
set videoactive 1
|
||||
}
|
||||
}
|
||||
|
||||
.ngmenu.file.video add command -label "add frame..." \
|
||||
-command {.ndraw Ng_VideoClip addframe }
|
||||
-command {Ng_VideoClip .ndraw addframe }
|
||||
|
||||
.ngmenu.file.video add command -label "one cycle" \
|
||||
-command {
|
||||
@ -383,14 +383,14 @@ set videoactive 0
|
||||
puts "j = $j"
|
||||
Ng_Vis_Set time [expr (1000 * $j / 100)]
|
||||
redraw
|
||||
.ndraw Ng_VideoClip addframe
|
||||
Ng_VideoClip .ndraw addframe
|
||||
after 200
|
||||
}
|
||||
}
|
||||
|
||||
.ngmenu.file.video add command -label "finalize..." \
|
||||
-command {
|
||||
.ndraw Ng_VideoClip finalize
|
||||
Ng_VideoClip .ndraw finalize
|
||||
global videoactive
|
||||
set videoactive 0
|
||||
}
|
||||
@ -1017,7 +1017,7 @@ proc timer2 { } {
|
||||
global videoactive
|
||||
if { $videoactive == 1 } {
|
||||
puts "addframe"
|
||||
.ndraw Ng_VideoClip addframe
|
||||
Ng_VideoClip .ndraw addframe
|
||||
}
|
||||
}
|
||||
if { $multithread_redraw == 2 } {
|
||||
@ -1028,7 +1028,7 @@ proc timer2 { } {
|
||||
global videoactive
|
||||
if { $videoactive == 1 } {
|
||||
puts "addframe"
|
||||
.ndraw Ng_VideoClip addframe
|
||||
Ng_VideoClip .ndraw addframe
|
||||
}
|
||||
after 1 { timer2 }
|
||||
return
|
||||
|
476
ng/ngpkg.cpp
476
ng/ngpkg.cpp
@ -24,11 +24,7 @@ The interface between the GUI and the netgen library
|
||||
|
||||
|
||||
// to be sure to include the 'right' togl-version
|
||||
#ifdef USE_TOGL_2
|
||||
#include "Togl2.1/togl.h"
|
||||
#else // USE_TOGL_2
|
||||
#include "togl_1_7.h"
|
||||
#endif // USE_TOGL_2
|
||||
#include "fonts.hpp"
|
||||
|
||||
extern bool nodisplay;
|
||||
@ -56,16 +52,7 @@ namespace netgen
|
||||
#endif
|
||||
|
||||
#ifdef FFMPEG
|
||||
extern "C" {
|
||||
/*
|
||||
#include <ffmpeg/avcodec.h>
|
||||
#include <ffmpeg/avformat.h>
|
||||
#include <ffmpeg/swscale.h>
|
||||
*/
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
}
|
||||
#include "encoding.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef NGSOLVE
|
||||
@ -1908,150 +1895,6 @@ namespace netgen
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if TOGL_MAJOR_VERSION==1
|
||||
|
||||
|
||||
// Togl
|
||||
|
||||
static int fontbase = 0;
|
||||
|
||||
void MyOpenGLText_GUI (const char * text)
|
||||
{
|
||||
if (nodisplay)
|
||||
return;
|
||||
|
||||
glListBase (fontbase);
|
||||
glCallLists (GLsizei(strlen(text)), GL_UNSIGNED_BYTE, text);
|
||||
}
|
||||
|
||||
static int
|
||||
Ng_ToglVersion(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
|
||||
{
|
||||
Tcl_SetResult (interp, (char*)"1", TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static void init( struct Togl *togl )
|
||||
{
|
||||
if (nodisplay)
|
||||
return;
|
||||
|
||||
LoadOpenGLFunctionPointers();
|
||||
fontbase = Togl_LoadBitmapFont( togl, TOGL_BITMAP_8_BY_13 );
|
||||
Set_OpenGLText_Callback (&MyOpenGLText_GUI);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
SetVisualScene (Togl_Interp(togl));
|
||||
vs->DrawScene();
|
||||
}
|
||||
|
||||
static void zap( struct Togl *togl )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void draw( struct Togl *togl )
|
||||
{
|
||||
if (nodisplay)
|
||||
return;
|
||||
|
||||
|
||||
int w = Togl_Width (togl);
|
||||
int h = Togl_Height (togl);
|
||||
|
||||
glViewport(0, 0, w, h);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
// OpenGL near and far clipping planes
|
||||
double pnear = 0.1;
|
||||
double pfar = 10;
|
||||
|
||||
gluPerspective(20.0f, double(w) / h, pnear, pfar);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
|
||||
|
||||
Tcl_Interp * interp = Togl_Interp(togl);
|
||||
|
||||
SetVisualScene (interp);
|
||||
|
||||
#ifdef STEREO
|
||||
if (1) // vispar.stereo)
|
||||
{
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
|
||||
glLoadIdentity ();
|
||||
|
||||
// glTranslatef (0.1, 0, 0);
|
||||
gluLookAt (0.3, 0, 6, 0, 0, 0, 0, 1, 0);
|
||||
Togl_StereoDrawBuffer(GL_BACK_RIGHT);
|
||||
vs->DrawScene();
|
||||
|
||||
glLoadIdentity ();
|
||||
// glTranslatef (-0.1, 0, 0);
|
||||
gluLookAt (-0.3, 0, 6, 0, 0, 0, 0, 1, 0);
|
||||
Togl_StereoDrawBuffer(GL_BACK_LEFT);
|
||||
vs->DrawScene();
|
||||
glPopMatrix();
|
||||
|
||||
Togl_SwapBuffers(togl);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
// gluLookAt (0, 0, 6, 0, 0, 0, 0, 1, 0);
|
||||
vs->DrawScene();
|
||||
glPopMatrix();
|
||||
Togl_SwapBuffers(togl);
|
||||
}
|
||||
}
|
||||
|
||||
static void reshape( struct Togl *togl)
|
||||
{
|
||||
/*
|
||||
if (nodisplay)
|
||||
return;
|
||||
|
||||
int w = Togl_Width (togl);
|
||||
int h = Togl_Height (togl);
|
||||
|
||||
glViewport(0, 0, w, h);
|
||||
netgen::VisualScene::viewport[0]=0;
|
||||
netgen::VisualScene::viewport[1]=0;
|
||||
netgen::VisualScene::viewport[2]=w;
|
||||
netgen::VisualScene::viewport[3]=h;
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
// OpenGL near and far clipping planes
|
||||
double pnear = 0.1;
|
||||
double pfar = 10;
|
||||
|
||||
gluPerspective(20.0f, double(w) / h, pnear, pfar);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
draw (togl);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
// Sorry, Togl 2.0 not supported
|
||||
|
||||
Font * font = nullptr;
|
||||
Togl * togl = NULL;
|
||||
|
||||
@ -2151,15 +1994,6 @@ namespace netgen
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if TOGL_MAJOR_VERSION==1
|
||||
|
||||
#ifndef JPEGLIB
|
||||
@ -2292,302 +2126,63 @@ namespace netgen
|
||||
#endif
|
||||
|
||||
|
||||
#else
|
||||
|
||||
// TODO: JPEGLIB for Togl2
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef FFMPEG
|
||||
static int Ng_VideoClip(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *const *argv)
|
||||
{
|
||||
static Mpeg mpeg;
|
||||
struct Togl *togl;
|
||||
if (Togl_GetToglFromObj(interp, argv[1], &togl) != TCL_OK)
|
||||
return TCL_ERROR;
|
||||
|
||||
// thanks to Mikko Lyly @ CSC, Helsinki
|
||||
|
||||
#define STATE_READY 0
|
||||
#define STATE_STARTED 1
|
||||
|
||||
|
||||
#define INBUF_SIZE 4096
|
||||
#define DEFAULT_B_FRAMES 3
|
||||
// #define DEFAULT_B_FRAMES 0
|
||||
#define DEFAULT_GOP_SIZE 200
|
||||
// #define DEFAULT_GOP_SIZE 10
|
||||
// #define DEFAULT_BITRATE 500000
|
||||
#define DEFAULT_BITRATE 5000000
|
||||
// #define DEFAULT_MPG_BUFSIZE 500000
|
||||
#define DEFAULT_MPG_BUFSIZE 500000
|
||||
|
||||
typedef struct buffer_s {
|
||||
uint8_t *MPG;
|
||||
uint8_t *YUV;
|
||||
uint8_t *RGB;
|
||||
uint8_t *ROW;
|
||||
} buffer_t;
|
||||
|
||||
void free_buffers( buffer_t *buff ) {
|
||||
free( buff->MPG );
|
||||
free( buff->YUV );
|
||||
free( buff->RGB );
|
||||
free( buff->ROW );
|
||||
}
|
||||
|
||||
static double psnr( double d ) {
|
||||
if( d==0 )
|
||||
return INFINITY;
|
||||
return -10.0*log( d )/log( 10.0 );
|
||||
}
|
||||
|
||||
void print_info( int count_frames, AVCodecContext *context, int bytes ) {
|
||||
double tmp = context->width * context->height * 255.0 * 255.0;
|
||||
double Ypsnr = psnr( context->coded_frame->error[0] / tmp );
|
||||
double quality = context->coded_frame->quality/(double)FF_QP2LAMBDA;
|
||||
char pict_type = av_get_picture_type_char(context->coded_frame->pict_type);
|
||||
cout << "video: frame=" << count_frames << " type=" << pict_type;
|
||||
cout << " size=" << bytes << " PSNR(Y)=" << Ypsnr << " dB q=" << (float)quality << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int Ng_VideoClip (struct Togl * togl,
|
||||
int argc, tcl_const char *argv[])
|
||||
{
|
||||
static AVCodec *codec = NULL;
|
||||
static AVCodecContext *context = NULL;
|
||||
static AVFrame *YUVpicture = NULL;
|
||||
static AVFrame *RGBpicture = NULL;
|
||||
static int bytes, PIXsize, stride;
|
||||
static int y, nx, ny;
|
||||
// static int ox, oy, viewp[4];
|
||||
static int i_state = STATE_READY;
|
||||
static int initialized = 0;
|
||||
static int count_frames = 0;
|
||||
static int bitrate = DEFAULT_BITRATE;
|
||||
static int gopsize = DEFAULT_GOP_SIZE;
|
||||
static int bframes = DEFAULT_B_FRAMES;
|
||||
static int MPGbufsize = DEFAULT_MPG_BUFSIZE;
|
||||
static AVCodecID codec_id = CODEC_ID_MPEG1VIDEO;
|
||||
static FILE *MPGfile;
|
||||
static buffer_t buff;
|
||||
static struct SwsContext *img_convert_ctx;
|
||||
|
||||
|
||||
if (strcmp (argv[2], "init") == 0)
|
||||
if (strcmp (Tcl_GetString(argv[2]), "init") == 0)
|
||||
{
|
||||
// Can't initialize when running:
|
||||
//-------------------------------
|
||||
if( i_state != STATE_READY ) {
|
||||
if( mpeg.IsStarted() ) {
|
||||
cout << "cannot initialize: already running" << endl;
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Open output file:
|
||||
//-------------------
|
||||
const char * filename = argv[3];
|
||||
cout << "Saving videoclip to file '" << filename << "'" << endl;
|
||||
MPGfile = fopen(filename, "wb");
|
||||
|
||||
// Determine picture size:
|
||||
//------------------------
|
||||
nx = Togl_Width (togl);
|
||||
nx = int((nx + 1) / 4) * 4 + 4;
|
||||
ny = Togl_Height (togl);
|
||||
ny = 2 * (ny/2);
|
||||
cout << "Width=" << nx << ", height=" << ny << endl;
|
||||
|
||||
// Allocate buffers:
|
||||
//------------------
|
||||
PIXsize = nx*ny;
|
||||
stride = 3*nx;
|
||||
buff.RGB = (uint8_t*)malloc(stride*ny);
|
||||
buff.ROW = (uint8_t*)malloc(stride);
|
||||
buff.YUV = (uint8_t*)malloc(3*(PIXsize/2));
|
||||
buff.MPG = (uint8_t*)malloc(MPGbufsize);
|
||||
|
||||
|
||||
// Initialize libavcodec:
|
||||
//-----------------------
|
||||
if( !initialized ) {
|
||||
av_register_all();
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
// Choose codec:
|
||||
//--------------
|
||||
codec = avcodec_find_encoder( codec_id );
|
||||
if( !codec ) {
|
||||
free_buffers( &buff );
|
||||
fclose( MPGfile );
|
||||
cout << "can't find codec" << endl;
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
// Init codec context etc.:
|
||||
//--------------------------
|
||||
// context = avcodec_alloc_context();
|
||||
context = avcodec_alloc_context3(codec);
|
||||
|
||||
context->bit_rate = bitrate;
|
||||
context->width = nx;
|
||||
context->height = ny;
|
||||
AVRational s;
|
||||
s.num = 1;
|
||||
s.den = 25;
|
||||
context->time_base = s;
|
||||
context->gop_size = gopsize;
|
||||
context->max_b_frames = bframes;
|
||||
context->pix_fmt = PIX_FMT_YUV420P;
|
||||
context->flags |= CODEC_FLAG_PSNR;
|
||||
|
||||
// if( avcodec_open( context, codec ) < 0 ) {
|
||||
if( avcodec_open2( context, codec, NULL) < 0 ) {
|
||||
cout << "can't open codec" << endl;
|
||||
avcodec_close( context );
|
||||
av_free( context );
|
||||
free_buffers( &buff );
|
||||
fclose( MPGfile );
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
YUVpicture = avcodec_alloc_frame();
|
||||
|
||||
YUVpicture->data[0] = buff.YUV;
|
||||
YUVpicture->data[1] = buff.YUV + PIXsize;
|
||||
YUVpicture->data[2] = buff.YUV + PIXsize + PIXsize / 4;
|
||||
YUVpicture->linesize[0] = nx;
|
||||
YUVpicture->linesize[1] = nx / 2;
|
||||
YUVpicture->linesize[2] = nx / 2;
|
||||
|
||||
RGBpicture = avcodec_alloc_frame();
|
||||
|
||||
RGBpicture->data[0] = buff.RGB;
|
||||
RGBpicture->data[1] = buff.RGB;
|
||||
RGBpicture->data[2] = buff.RGB;
|
||||
RGBpicture->linesize[0] = stride;
|
||||
RGBpicture->linesize[1] = stride;
|
||||
RGBpicture->linesize[2] = stride;
|
||||
|
||||
// Set state "started":
|
||||
//----------------------
|
||||
i_state = STATE_STARTED;
|
||||
cout << "savempg: state: started" << endl;
|
||||
const char * filename = Tcl_GetString(argv[3]);
|
||||
mpeg.Start(filename);
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
else if (strcmp (argv[2], "addframe") == 0)
|
||||
else if (strcmp (Tcl_GetString(argv[2]), "addframe") == 0)
|
||||
{
|
||||
// Can't compress if status != started:
|
||||
//-------------------------------------
|
||||
if( i_state != STATE_STARTED ) {
|
||||
cout << "cannot add frame: codec not initialized" << endl;
|
||||
if(mpeg.AddFrame())
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
// Read RGB data:
|
||||
//---------------
|
||||
glReadPixels (0, 0, nx, ny, GL_RGB, GL_UNSIGNED_BYTE, buff.RGB );
|
||||
|
||||
// The picture is upside down - flip it:
|
||||
//---------------------------------------
|
||||
for( y=0; y<ny/2; y++ ) {
|
||||
uint8_t *r1 = buff.RGB + stride*y;
|
||||
uint8_t *r2 = buff.RGB + stride*(ny-1-y);
|
||||
memcpy( buff.ROW, r1, stride );
|
||||
memcpy( r1, r2, stride );
|
||||
memcpy( r2, buff.ROW, stride );
|
||||
}
|
||||
|
||||
// Convert to YUV:
|
||||
//----------------
|
||||
if( img_convert_ctx == NULL )
|
||||
img_convert_ctx = sws_getContext( nx, ny, PIX_FMT_RGB24,
|
||||
nx, ny, PIX_FMT_YUV420P,
|
||||
SWS_BICUBIC, NULL, NULL, NULL );
|
||||
|
||||
if( img_convert_ctx == NULL ) {
|
||||
cout << "can't initialize scaler context" << endl;
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
sws_scale( img_convert_ctx, RGBpicture->data, RGBpicture->linesize,
|
||||
0, ny, YUVpicture->data, YUVpicture->linesize );
|
||||
|
||||
|
||||
// Encode frame:
|
||||
//--------------
|
||||
bytes = avcodec_encode_video( context, buff.MPG,
|
||||
MPGbufsize, YUVpicture );
|
||||
count_frames++;
|
||||
print_info( count_frames, context, bytes );
|
||||
fwrite( buff.MPG, 1, bytes, MPGfile );
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
else if (strcmp (argv[2], "finalize") == 0)
|
||||
else if (strcmp (Tcl_GetString(argv[2]), "finalize") == 0)
|
||||
{
|
||||
// Can't stop if status != started:
|
||||
//---------------------------------
|
||||
if( i_state != STATE_STARTED ) {
|
||||
cout << "cannot finalize: codec not initialized" << endl;
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
// Get the delayed frames, if any:
|
||||
//--------------------------------
|
||||
for( ; bytes; ) {
|
||||
bytes = avcodec_encode_video( context, buff.MPG, MPGbufsize, NULL );
|
||||
count_frames++;
|
||||
print_info( count_frames, context, bytes );
|
||||
fwrite( buff.MPG, 1, bytes, MPGfile );
|
||||
}
|
||||
|
||||
// Add sequence end code:
|
||||
//-----------------------
|
||||
if( codec_id == CODEC_ID_MPEG1VIDEO ) {
|
||||
buff.MPG[0] = 0x00;
|
||||
buff.MPG[1] = 0x00;
|
||||
buff.MPG[2] = 0x01;
|
||||
buff.MPG[3] = 0xb7;
|
||||
fwrite( buff.MPG, 1, 4, MPGfile );
|
||||
}
|
||||
|
||||
// Finalize:
|
||||
//-----------
|
||||
avcodec_close( context );
|
||||
av_free( context );
|
||||
av_free( YUVpicture );
|
||||
av_free( RGBpicture );
|
||||
free_buffers( &buff );
|
||||
fclose( MPGfile );
|
||||
|
||||
i_state = STATE_READY;
|
||||
cout << "finalized" << endl;
|
||||
|
||||
return TCL_OK;
|
||||
mpeg.Stop();
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
static int Ng_VideoClip (struct Togl * togl,
|
||||
int argc, tcl_const char *argv[])
|
||||
#else // FFMPEG
|
||||
static int Ng_VideoClip(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *const *argv)
|
||||
{
|
||||
Tcl_SetResult (Togl_Interp(togl), (char*)"Video not available, Netgen was not compiled with FFMPEG library", TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // FFMPEG
|
||||
|
||||
|
||||
|
||||
@ -3476,22 +3071,6 @@ void PlayAnimFile(const char* name, int speed, int maxcnt)
|
||||
*/
|
||||
Tcl_CreateObjCommand(interp, "Ng_GetToglVersion", Ng_ToglVersion, NULL, NULL);
|
||||
|
||||
#if TOGL_MAJOR_VERSION==1
|
||||
if (!nodisplay)
|
||||
{
|
||||
if (Togl_Init(interp) == TCL_ERROR)
|
||||
return TCL_ERROR;
|
||||
|
||||
Togl_CreateFunc( init );
|
||||
Togl_DestroyFunc( zap );
|
||||
Togl_DisplayFunc( draw );
|
||||
Togl_ReshapeFunc( reshape );
|
||||
// Togl_TimerFunc( idle );
|
||||
Togl_CreateCommand( (char*)"Ng_SnapShot", Ng_SnapShot);
|
||||
Togl_CreateCommand( (char*)"Ng_VideoClip", Ng_VideoClip);
|
||||
// Togl_CreateCommand("position",position);
|
||||
}
|
||||
#else
|
||||
if (!nodisplay)
|
||||
{
|
||||
if (Togl_Init(interp) == TCL_ERROR)
|
||||
@ -3505,12 +3084,9 @@ void PlayAnimFile(const char* name, int speed, int maxcnt)
|
||||
|
||||
// Togl_TimerFunc( idle );
|
||||
// Togl_CreateCommand( (char*)"Ng_SnapShot", Ng_SnapShot);
|
||||
// Togl_CreateCommand( (char*)"Ng_VideoClip", Ng_VideoClip);
|
||||
// Togl_CreateCommand("position",position);
|
||||
Tcl_CreateObjCommand(interp, "Ng_VideoClip", Ng_VideoClip, NULL, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
multithread.pause = 0;
|
||||
multithread.testmode = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user