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_CCACHE
|
||||||
USE_NATIVE_ARCH
|
USE_NATIVE_ARCH
|
||||||
USE_OCC
|
USE_OCC
|
||||||
|
USE_MPEG
|
||||||
INSTALL_DIR
|
INSTALL_DIR
|
||||||
INSTALL_DEPENDENCIES
|
INSTALL_DEPENDENCIES
|
||||||
INTEL_MIC
|
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
|
global videoactive
|
||||||
if { $videoactive == 1 } {
|
if { $videoactive == 1 } {
|
||||||
puts "addframe"
|
puts "addframe"
|
||||||
.ndraw Ng_VideoClip addframe
|
Ng_VideoClip .ndraw addframe
|
||||||
}
|
}
|
||||||
if { $result == 0 && $stopdemo == 0 } {
|
if { $result == 0 && $stopdemo == 0 } {
|
||||||
after 1 { demoredraw }
|
after 1 { demoredraw }
|
||||||
@ -367,14 +367,14 @@ set videoactive 0
|
|||||||
}
|
}
|
||||||
set file [tk_getSaveFile -filetypes $types]
|
set file [tk_getSaveFile -filetypes $types]
|
||||||
if {$file != ""} {
|
if {$file != ""} {
|
||||||
.ndraw Ng_VideoClip init $file
|
Ng_VideoClip .ndraw init $file
|
||||||
global videoactive
|
global videoactive
|
||||||
set videoactive 1
|
set videoactive 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ngmenu.file.video add command -label "add frame..." \
|
.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" \
|
.ngmenu.file.video add command -label "one cycle" \
|
||||||
-command {
|
-command {
|
||||||
@ -383,14 +383,14 @@ set videoactive 0
|
|||||||
puts "j = $j"
|
puts "j = $j"
|
||||||
Ng_Vis_Set time [expr (1000 * $j / 100)]
|
Ng_Vis_Set time [expr (1000 * $j / 100)]
|
||||||
redraw
|
redraw
|
||||||
.ndraw Ng_VideoClip addframe
|
Ng_VideoClip .ndraw addframe
|
||||||
after 200
|
after 200
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ngmenu.file.video add command -label "finalize..." \
|
.ngmenu.file.video add command -label "finalize..." \
|
||||||
-command {
|
-command {
|
||||||
.ndraw Ng_VideoClip finalize
|
Ng_VideoClip .ndraw finalize
|
||||||
global videoactive
|
global videoactive
|
||||||
set videoactive 0
|
set videoactive 0
|
||||||
}
|
}
|
||||||
@ -1017,7 +1017,7 @@ proc timer2 { } {
|
|||||||
global videoactive
|
global videoactive
|
||||||
if { $videoactive == 1 } {
|
if { $videoactive == 1 } {
|
||||||
puts "addframe"
|
puts "addframe"
|
||||||
.ndraw Ng_VideoClip addframe
|
Ng_VideoClip .ndraw addframe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if { $multithread_redraw == 2 } {
|
if { $multithread_redraw == 2 } {
|
||||||
@ -1028,7 +1028,7 @@ proc timer2 { } {
|
|||||||
global videoactive
|
global videoactive
|
||||||
if { $videoactive == 1 } {
|
if { $videoactive == 1 } {
|
||||||
puts "addframe"
|
puts "addframe"
|
||||||
.ndraw Ng_VideoClip addframe
|
Ng_VideoClip .ndraw addframe
|
||||||
}
|
}
|
||||||
after 1 { timer2 }
|
after 1 { timer2 }
|
||||||
return
|
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
|
// to be sure to include the 'right' togl-version
|
||||||
#ifdef USE_TOGL_2
|
|
||||||
#include "Togl2.1/togl.h"
|
#include "Togl2.1/togl.h"
|
||||||
#else // USE_TOGL_2
|
|
||||||
#include "togl_1_7.h"
|
|
||||||
#endif // USE_TOGL_2
|
|
||||||
#include "fonts.hpp"
|
#include "fonts.hpp"
|
||||||
|
|
||||||
extern bool nodisplay;
|
extern bool nodisplay;
|
||||||
@ -56,16 +52,7 @@ namespace netgen
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef FFMPEG
|
#ifdef FFMPEG
|
||||||
extern "C" {
|
#include "encoding.hpp"
|
||||||
/*
|
|
||||||
#include <ffmpeg/avcodec.h>
|
|
||||||
#include <ffmpeg/avformat.h>
|
|
||||||
#include <ffmpeg/swscale.h>
|
|
||||||
*/
|
|
||||||
#include <libavcodec/avcodec.h>
|
|
||||||
#include <libavformat/avformat.h>
|
|
||||||
#include <libswscale/swscale.h>
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NGSOLVE
|
#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;
|
Font * font = nullptr;
|
||||||
Togl * togl = NULL;
|
Togl * togl = NULL;
|
||||||
|
|
||||||
@ -2151,15 +1994,6 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if TOGL_MAJOR_VERSION==1
|
#if TOGL_MAJOR_VERSION==1
|
||||||
|
|
||||||
#ifndef JPEGLIB
|
#ifndef JPEGLIB
|
||||||
@ -2292,302 +2126,63 @@ namespace netgen
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// TODO: JPEGLIB for Togl2
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef FFMPEG
|
#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
|
if (strcmp (Tcl_GetString(argv[2]), "init") == 0)
|
||||||
|
|
||||||
#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)
|
|
||||||
{
|
{
|
||||||
// Can't initialize when running:
|
// Can't initialize when running:
|
||||||
//-------------------------------
|
//-------------------------------
|
||||||
if( i_state != STATE_READY ) {
|
if( mpeg.IsStarted() ) {
|
||||||
cout << "cannot initialize: already running" << endl;
|
cout << "cannot initialize: already running" << endl;
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char * filename = Tcl_GetString(argv[3]);
|
||||||
|
mpeg.Start(filename);
|
||||||
// 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;
|
|
||||||
|
|
||||||
return TCL_OK;
|
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(mpeg.AddFrame())
|
||||||
//-------------------------------------
|
|
||||||
if( i_state != STATE_STARTED ) {
|
|
||||||
cout << "cannot add frame: codec not initialized" << endl;
|
|
||||||
return TCL_ERROR;
|
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:
|
mpeg.Stop();
|
||||||
//---------------------------------
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else // FFMPEG
|
||||||
|
static int Ng_VideoClip(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *const *argv)
|
||||||
#else
|
|
||||||
static int Ng_VideoClip (struct Togl * togl,
|
|
||||||
int argc, tcl_const char *argv[])
|
|
||||||
{
|
{
|
||||||
Tcl_SetResult (Togl_Interp(togl), (char*)"Video not available, Netgen was not compiled with FFMPEG library", TCL_STATIC);
|
Tcl_SetResult (Togl_Interp(togl), (char*)"Video not available, Netgen was not compiled with FFMPEG library", TCL_STATIC);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
#endif
|
#endif // FFMPEG
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -3476,22 +3071,6 @@ void PlayAnimFile(const char* name, int speed, int maxcnt)
|
|||||||
*/
|
*/
|
||||||
Tcl_CreateObjCommand(interp, "Ng_GetToglVersion", Ng_ToglVersion, NULL, NULL);
|
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 (!nodisplay)
|
||||||
{
|
{
|
||||||
if (Togl_Init(interp) == TCL_ERROR)
|
if (Togl_Init(interp) == TCL_ERROR)
|
||||||
@ -3505,12 +3084,9 @@ void PlayAnimFile(const char* name, int speed, int maxcnt)
|
|||||||
|
|
||||||
// Togl_TimerFunc( idle );
|
// Togl_TimerFunc( idle );
|
||||||
// Togl_CreateCommand( (char*)"Ng_SnapShot", Ng_SnapShot);
|
// Togl_CreateCommand( (char*)"Ng_SnapShot", Ng_SnapShot);
|
||||||
// Togl_CreateCommand( (char*)"Ng_VideoClip", Ng_VideoClip);
|
Tcl_CreateObjCommand(interp, "Ng_VideoClip", Ng_VideoClip, NULL, NULL);
|
||||||
// Togl_CreateCommand("position",position);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
multithread.pause = 0;
|
multithread.pause = 0;
|
||||||
multithread.testmode = 0;
|
multithread.testmode = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user