summaryrefslogtreecommitdiff
path: root/rotord/src
diff options
context:
space:
mode:
Diffstat (limited to 'rotord/src')
-rw-r--r--rotord/src/graph.cpp148
-rw-r--r--rotord/src/graph.h5
-rw-r--r--rotord/src/libavwrapper.cpp66
-rw-r--r--rotord/src/libavwrapper.h107
-rw-r--r--rotord/src/rotor.h16
5 files changed, 295 insertions, 47 deletions
diff --git a/rotord/src/graph.cpp b/rotord/src/graph.cpp
index 5487717..29b46be 100644
--- a/rotord/src/graph.cpp
+++ b/rotord/src/graph.cpp
@@ -106,6 +106,154 @@ bool Graph::video_render(const string &output_filename,const float framerate) {
if (exporter.setup(outW,outH,bitRate,framerate,container)) { //codecId,
if (exporter.record(output_filename)) {
+ libav::audio_decoder audioloader;
+
+ bool usingaudio=audioloader.open(audio_filename);
+ float *avframe=nullptr;
+
+ Logger& logger = Logger::get("Rotor");
+ logger.information("Video_output rendering "+output_filename+": "+toString(duration)+" seconds at "+toString(framerate)+" fps, audio frame size: "+toString(exporter.get_audio_framesize()));
+ //25fps video and 43.06640625fps audio? hmm
+ //how to get the timecodes correct for the interleaved files
+
+ struct timeval start, end;
+
+ gettimeofday(&start, NULL);
+
+ uint16_t *audioframe=nullptr;
+ uint16_t *audio=nullptr;
+ int samples_in_frame;
+
+ if (usingaudio){
+ samples_in_frame=(audioloader.get_sample_rate())/framerate;
+ string whether=usingaudio?"Loading":"Cannot load";
+ logger.information(whether+" audio file: "+audio_filename+", each frame contains "+toString(samples_in_frame)+" samples at "+toString(audioloader.get_sample_rate())+" hz");
+ audioframe=new uint16_t[(samples_in_frame+exporter.get_audio_framesize())*audioloader.get_number_channels()];
+ audio=new uint16_t[samples_in_frame*audioloader.get_number_channels()];
+ }
+
+ float vstep=1.0f/framerate;
+ float v=0.0f;
+ float vf=0.0f;
+ float af=0.0f;
+ int aoffs=0;
+ int audioend=0;
+ Audio_frame *a;
+ int64_t sample_start=0;
+ while (vf<duration&&!cancelled){ //-vstep) {
+
+ if (usingaudio) {
+ if (audioloader.get_samples(audio,sample_start,samples_in_frame)) {
+ if (aoffs>0){
+ //shift down samples
+ int s=0;
+ while ((s+aoffs)<audioend) {
+ for (int j=0;j<audioloader.get_number_channels();j++){
+ audioframe[s*audioloader.get_number_channels()+j]=audioframe[(s+aoffs)*audioloader.get_number_channels()+j];
+ }
+ s++;
+ }
+ aoffs=s;
+ }
+ for (int i=0;i<samples_in_frame;i++){
+ for (int j=0;j<audioloader.get_number_channels();j++){
+ audioframe[(aoffs+i)*audioloader.get_number_channels()+j]=audio[i*audioloader.get_number_channels()+j];
+ }
+ }
+ audioend=aoffs+samples_in_frame;
+ aoffs=0;
+ while (aoffs+exporter.get_audio_framesize()<audioend) {
+ //insert audio frames until we are only 1 audio frame behind the next video frame
+ //send audio_framesize() of them through until buffer is used
+ //pass full buffer within frame_spec for av nodes
+ exporter.encodeFrame(audioframe+(aoffs*audioloader.get_number_channels()));
+ af+=exporter.get_audio_step();
+ aoffs+=exporter.get_audio_framesize();
+ }
+ a=new Audio_frame(audio,audioloader.get_number_channels(),samples_in_frame);
+ sample_start+=samples_in_frame;
+ }
+
+ }
+
+
+ //[mp3 @ 0x7fffe40330e0] max_analyze_duration 5000000 reached at 5015510 microseconds
+ //[mp3 @ 0x7fffe4033ec0] Insufficient thread locking around avcodec_open/close()
+ //[mp3 @ 0x7fffe40330e0] Estimating duration from bitrate, this may be inaccurate
+ //[libx264 @ 0x7fffe8003940] using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE4.2
+ //[libx264 @ 0x7fffe8003940] profile High, level 3.0
+ //[libx264 @ 0x7fffe8003940] 264 - core 123 r2189 35cf912 - H.264/MPEG-4 AVC codec - Copyleft 2003-2012 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=12 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=10 keyint_min=1 scenecut=40 intra_refresh=0 rc_lookahead=10 rc=abr mbtree=1 bitrate=400 ratetol=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
+ //Assertion ff_avcodec_locked failed at libavcodec/utils.c:2967
+
+ //cerr<<"videoloader: "<<vf<<" seconds, vstep "<<vstep<<" ,asking for frame "<<((int)((vf*framerate)+0.5))<<endl
+
+ Image* i;
+ if (usingaudio) {
+ i=video_output->get_output(Frame_spec(vf,framerate,duration,outW,outH,a));
+ }
+ else i=video_output->get_output(Frame_spec(vf,framerate,duration,outW,outH));
+ if (i) {
+ exporter.encodeFrame(i->RGBdata);
+ }
+ vf+=vstep;
+ progress=vf/duration;
+ if (usingaudio) {delete a;};
+ }
+
+ exporter.finishRecord();
+
+ gettimeofday(&end, NULL);
+
+ float mtime = ((end.tv_sec-start.tv_sec) + (end.tv_usec-start.tv_usec)/1000000.0) + 0.5;
+
+ logger.information("Video_output: rendered "+output_filename+": in "+toString(mtime)+" seconds");
+
+ if (usingaudio) {
+ audioloader.cleanup();
+ delete[] audioframe;
+ delete[] audio;
+ }
+
+
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ cerr<<"Rotor: video output node not found"<<endl;
+ return false;
+}
+
+bool Graph::_video_render(const string &output_filename,const float framerate) {
+ //vector<Node*> loaders=find_nodes("video_loader");
+ //for (auto i:loaders){
+ // if (!dynamic_cast<Video_loader*>(i)->isLoaded) {
+ // cerr<<"Rotor: all loaders must be populated before rendering"<<endl;
+ // return false;
+ // }
+ //}
+ if (find_node("video_output")) {
+ Video_output *video_output=dynamic_cast<Video_output*>(find_node("video_output"));
+ for (auto f: find_nodes("video_feedback")){
+ (dynamic_cast<Video_feedback*>(f))->set_feedback(&(video_output->image));
+ }
+ //
+ //setup defaults
+ int bitRate=5000000;
+ AVCodecID codecId=AV_CODEC_ID_H264; //MPEG4;
+ std::string container ="mp4";
+
+ //at the moment it crashes if you render before audio is loaded and also on 2nd render
+ libav::exporter exporter;
+
+ float spct=100.0f/duration;
+
+ if (exporter.setup(outW,outH,bitRate,framerate,container)) { //codecId,
+ if (exporter.record(output_filename)) {
+
libav::audioloader audioloader;
bool usingaudio=audioloader.setup(audio_filename);
diff --git a/rotord/src/graph.h b/rotord/src/graph.h
index 6a2fc2d..9207559 100644
--- a/rotord/src/graph.h
+++ b/rotord/src/graph.h
@@ -42,6 +42,7 @@ namespace Rotor {
vector<Node*> find_nodes(const string &type); //could be a way of finding a set based on capabilities?
Node* find_node(const string &type);
bool signal_render(string &signal_xml,const float framerate);
+ bool _video_render(const string &output_filename,const float framerate);
bool video_render(const string &output_filename,const float framerate);
bool load(string data,string media_path);
bool loadFile(string &filename,string media_path);
@@ -70,7 +71,7 @@ namespace Rotor {
public:
bool make(const string &inputfilename,int w,int h,const string &outputfilename) {
if (player.open(inputfilename)){
- if (player.fetchFrame(w,h,player.getNumberOfFrames()/4)) {
+ if (player.fetch_frame(w,h,player.get_number_frames()/4)) {
Image i;
i.setup_fromRGB(w,h,player.frame->Data[0],player.frame->Linesize[0]-(w*3));
cv::Mat cp;
@@ -83,7 +84,7 @@ namespace Rotor {
return false;
}
private:
- libav::ffms2_decoder player;
+ libav::video_decoder player;
};
}
#endif
diff --git a/rotord/src/libavwrapper.cpp b/rotord/src/libavwrapper.cpp
index 717667c..1fe0e5a 100644
--- a/rotord/src/libavwrapper.cpp
+++ b/rotord/src/libavwrapper.cpp
@@ -557,45 +557,45 @@ bool libav::decoder::avtry(int result, const std::string& msg) {
return true;
}
- void libav::ffms2_decoder::cleanup(){
+ void libav::video_decoder::cleanup(){
if (loaded) {
mutex.lock();
- FFMS_DestroyVideoSource(videosource);
+ FFMS_DestroyVideoSource(source);
mutex.unlock();
loaded=false;
}
}
-bool libav::ffms2_decoder::open(const std::string& filename){
+bool libav::video_decoder::open(const std::string& filename){
mutex.lock();
loaded=false;
- FFMS_Index *index = FFMS_MakeIndex(filename.c_str(), 0, 0, NULL, NULL, FFMS_IEH_IGNORE, NULL, NULL, &errinfo);
+ FFMS_Index *index = FFMS_MakeIndex(filename.c_str(), 0, 0, NULL, NULL, FFMS_IEH_IGNORE, NULL, NULL, &err);
if (index == NULL) {
- std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl;
+ std::cerr<<"ffmpegsource: "<<err.Buffer<<std::endl;
mutex.unlock();
return false;
}
- int trackno = FFMS_GetFirstTrackOfType(index, FFMS_TYPE_VIDEO, &errinfo);
+ int trackno = FFMS_GetFirstTrackOfType(index, FFMS_TYPE_VIDEO, &err);
if (trackno < 0) {
- std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl;
+ std::cerr<<"ffmpegsource: "<<err.Buffer<<std::endl;
mutex.unlock();
return false;
}
- videosource = FFMS_CreateVideoSource(filename.c_str(), trackno, index, 1, FFMS_SEEK_NORMAL, &errinfo);
- if (videosource == NULL) {
- std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl;
+ source = FFMS_CreateVideoSource(filename.c_str(), trackno, index, 1, FFMS_SEEK_NORMAL, &err);
+ if (source == NULL) {
+ std::cerr<<"ffmpegsource: "<<err.Buffer<<std::endl;
mutex.unlock();
return false;
}
FFMS_DestroyIndex(index);
- videoprops = FFMS_GetVideoProperties(videosource);
- const FFMS_Frame *propframe = FFMS_GetFrame(videosource, 0, &errinfo);
+ props = FFMS_GetVideoProperties(source);
+ const FFMS_Frame *propframe = FFMS_GetFrame(source, 0, &err);
w=propframe->EncodedWidth;
h=propframe->EncodedHeight;
//propframe->EncodedPixelFormat;
- if (FFMS_SetOutputFormatV2(videosource, pixfmts, propframe->EncodedWidth, propframe->EncodedHeight, FFMS_RESIZER_BICUBIC, &errinfo)) {
- std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl;
+ if (FFMS_SetOutputFormatV2(source, pixfmts, propframe->EncodedWidth, propframe->EncodedHeight, FFMS_RESIZER_BICUBIC, &err)) {
+ std::cerr<<"ffmpegsource: "<<err.Buffer<<std::endl;
mutex.unlock();
return false;
}
@@ -608,6 +608,44 @@ bool libav::ffms2_decoder::open(const std::string& filename){
return loaded;
}
+bool libav::audio_decoder::open(const std::string& filename){
+ mutex.lock();
+ loaded=false;
+ FFMS_Index *index = FFMS_MakeIndex(filename.c_str(),-1, 0, NULL, NULL, FFMS_IEH_IGNORE, NULL, NULL, &err);
+ if (index == NULL) {
+ std::cerr<<"ffmpegsource error making index for "<<filename<<":"<<err.Buffer<<std::endl;
+ mutex.unlock();
+ return false;
+ }
+ int trackno = FFMS_GetFirstTrackOfType(index, FFMS_TYPE_AUDIO, &err);
+ if (trackno < 0) {
+ std::cerr<<"ffmpegsource error finding audio track in "<<filename<<":"<<err.Buffer<<std::endl;
+ mutex.unlock();
+ return false;
+ }
+ std::cerr<<"ffmpegsource found audio track "<<trackno<<" in "<<filename<<":"<<err.Buffer<<std::endl;
+ source = FFMS_CreateAudioSource(filename.c_str(), trackno, index, FFMS_DELAY_TIME_ZERO, &err);
+ if (source == NULL) {
+ std::cerr<<"ffmpegsource error creating audio source from "<<filename<<":"<<err.Buffer<<std::endl;
+ mutex.unlock();
+ return false;
+ }
+ FFMS_DestroyIndex(index);
+ props = FFMS_GetAudioProperties(source);
+
+ std::cerr<<"ffmpegsource: successfully opened "<<filename<<std::endl;
+ loaded=true;
+ mutex.unlock();
+ return loaded;
+}
+ void libav::audio_decoder::cleanup(){
+ if (loaded) {
+ mutex.lock();
+ FFMS_DestroyAudioSource(source);
+ mutex.unlock();
+ loaded=false;
+ }
+}
///////////////////////////
// encoder methods //
///////////////////////////
diff --git a/rotord/src/libavwrapper.h b/rotord/src/libavwrapper.h
index 870815f..2f1f31e 100644
--- a/rotord/src/libavwrapper.h
+++ b/rotord/src/libavwrapper.h
@@ -156,68 +156,129 @@ namespace libav {
};
- class ffms2_decoder
+ class video_decoder
{
public:
- ffms2_decoder(){
+ video_decoder(){
maybeInitFFMpegLib();
pixfmts[0] = FFMS_GetPixFmt("rgb24");
pixfmts[1] = -1;
h=0;
w=0;
- videosource=NULL;
+ source=NULL;
loaded=false;
- errinfo.Buffer = errmsg;
- errinfo.BufferSize = sizeof(errmsg);
- errinfo.ErrorType = FFMS_ERROR_SUCCESS;
- errinfo.SubType = FFMS_ERROR_SUCCESS;
+ err.Buffer = errmsg;
+ err.BufferSize = sizeof(errmsg);
+ err.ErrorType = FFMS_ERROR_SUCCESS;
+ err.SubType = FFMS_ERROR_SUCCESS;
}
- ~ffms2_decoder(){
+ ~video_decoder(){
cleanup();
}
void cleanup();
bool open(const std::string& filename);
- float getFrameRate(){
- if (loaded) return (((float)videoprops->FPSNumerator)/((float)videoprops->FPSDenominator));
+ float get_framerate(){
+ if (loaded) return (((float)props->FPSNumerator)/((float)props->FPSDenominator));
else return -1.0f;
}
- int getNumberOfFrames(){
- if (loaded) return videoprops->NumFrames;
+ int get_number_frames(){
+ if (loaded) return props->NumFrames;
else return -1;
}
- int getNumberOfChannels(){
+ int get_number_channels(){
return 3; //this is what we convert to
}
- int getWidth(){
+ int get_width(){
return w;
}
- int getHeight(){
+ int get_height(){
return h;
}
- bool fetchFrame(int width,int height,int wanted){
- if (FFMS_SetOutputFormatV2(videosource, pixfmts, width, height, FFMS_RESIZER_BICUBIC, &errinfo)) {
- std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl;
+ bool fetch_frame(int width,int height,int wanted){
+ if (FFMS_SetOutputFormatV2(source, pixfmts, width, height, FFMS_RESIZER_BICUBIC, &err)) {
+ std::cerr<<"ffmpegsource: "<<err.Buffer<<std::endl;
return false;
}
- frame = FFMS_GetFrame(videosource, wanted%videoprops->NumFrames, &errinfo);
+ frame = FFMS_GetFrame(source, wanted%props->NumFrames, &err);
if (frame == NULL) {
- std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl;
+ std::cerr<<"ffmpegsource: "<<err.Buffer<<std::endl;
return false;
}
return true;
}
- FFMS_VideoSource *videosource;
- FFMS_VideoProperties *videoprops;
+ FFMS_VideoSource *source;
+ FFMS_VideoProperties *props;
FFMS_Frame *frame;
- FFMS_ErrorInfo errinfo;
+ FFMS_ErrorInfo err;
char errmsg[1024];
int pixfmts[2];
bool loaded;
int h,w;
};
+ class audio_decoder
+ {
+ public:
+ audio_decoder(){
+ maybeInitFFMpegLib();
+ source=nullptr;
+ props=nullptr;
+ loaded=false;
+ err.Buffer = errmsg;
+ err.BufferSize = sizeof(errmsg);
+ err.ErrorType = FFMS_ERROR_SUCCESS;
+ err.SubType = FFMS_ERROR_SUCCESS;
+ }
+ ~audio_decoder(){
+ cleanup();
+ }
+ void cleanup();
+ bool open(const std::string& filename);
+ int get_format(){
+ if (props) return props->SampleFormat;
+ else return 0;
+ }
+ int get_sample_rate(){
+ if (props) return props->SampleRate;
+ else return 0;
+ }
+ int get_bit_depth(){
+ if (props) return props->BitsPerSample;
+ else return 0;
+ }
+ int get_number_channels(){
+ if (props) return props->Channels;
+ else return 0;
+ }
+ int64_t get_channel_layout(){
+ if (props) return props->ChannelLayout;
+ else return 0;
+ }
+ float get_duration(){
+ if (props) return ((float)props->NumSamples)/props->SampleRate;
+ else return 0;
+ }
+ bool get_samples(void *buf,int64_t start, int64_t count){
+ if (source) {
+ if (FFMS_GetAudio(source, buf, start, count, &err)) {
+ std::cerr<<"ffmpegsource: "<<err.Buffer<<std::endl;
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ FFMS_AudioSource *source;
+ FFMS_AudioProperties *props;
+ FFMS_Frame *frame;
+ FFMS_ErrorInfo err;
+ char errmsg[1024];
+ bool loaded;
+ };
+
/*
// TODO - finish refactoring based on
// http://svn.gnumonks.org/trunk/21c3-video/ffmpeg/ffmpeg-0.4.9-pre1/output_example.c
diff --git a/rotord/src/rotor.h b/rotord/src/rotor.h
index ff8675a..447ba51 100644
--- a/rotord/src/rotor.h
+++ b/rotord/src/rotor.h
@@ -933,10 +933,10 @@ namespace Rotor {
isLoaded=player.open(filename);
if (isLoaded){
logger.information("Video_loader loaded "+filename+": "\
- +toString(player.getNumberOfFrames())+" frames, "\
- +toString(player.getFrameRate())+" fps, "\
- +toString(player.getWidth())+"x"+toString(player.getHeight())\
- +", channels:"+toString(player.getNumberOfChannels()));
+ +toString(player.get_number_frames())+" frames, "\
+ +toString(player.get_framerate())+" fps, "\
+ +toString(player.get_width())+"x"+toString(player.get_height())\
+ +", channels:"+toString(player.get_number_channels()));
return true;
}
logger.error("Video_loader failed to load "+filename);
@@ -944,11 +944,11 @@ namespace Rotor {
}
Image *output(const Frame_spec &frame){
if (isLoaded){
- float clipframerate=(parameters["framerate"]->value==0.0f?player.getFrameRate():parameters["framerate"]->value);
+ float clipframerate=(parameters["framerate"]->value==0.0f?player.get_framerate():parameters["framerate"]->value);
float clipspeed=(clipframerate/frame.framerate)*parameters["speed"]->value;
- int wanted=(((int) ((frame.time*frame.framerate)+0.5))%max(1,player.getNumberOfFrames()-1));
+ int wanted=(((int) ((frame.time*frame.framerate)+0.5))%max(1,player.get_number_frames()-1));
if (wanted!=lastframe){
- if (!player.fetchFrame(frame.w,frame.h,wanted)) { //seek fail
+ if (!player.fetch_frame(frame.w,frame.h,wanted)) { //seek fail
Poco::Logger& logger = Poco::Logger::get("Rotor");
logger.error("Video_loader failed to seek frame "+toString(wanted)+" of "+attributes["filename"]->value);
@@ -966,7 +966,7 @@ namespace Rotor {
bool isLoaded;
private:
//ffmpegsource::decoder player;
- libav::ffms2_decoder player;
+ libav::video_decoder player;
int lastframe;
};
class Video_output: public Image_node {