summaryrefslogtreecommitdiff
path: root/rotord/src/graph.h
blob: a231c2975de9b7db7caa0da3c07aeddf13d9d5f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#ifndef GRAPH_H
#define GRAPH_H

#include "Poco/StringTokenizer.h"

#include "rotor.h"
#include "nodes_signals.h"
#include "nodes_audio_analysis.h"


/*------------------------

Graph is an instance of a rotor renderer

tidy up loading stuff
kill xml or retain?
make codebase closer

-validate loader menthod
get number of nodes
copy nodes `

-------------------------*/

namespace Rotor {
	class Graph{
		public:
			Graph(){duration=20.0f;loaded = false;audio_loaded=false;bitRate=0;outW=640;outH=360;audio_thumb=new Audio_thumbnailer();use_fragmentation=false;analysis_seed=0;};
			Graph(const string& _uid,const string& _desc){
				Graph();
				init(_uid,_desc);
			};
			void init(const string& _uid,const string& _desc){
				uid=_uid;
				description=_desc;
				duration=20.0f;
				framerate=25.0f;
				cancelled=false;
			};
			~Graph(){ clear(); delete audio_thumb;};
			void clear(){
				for (auto n: nodes) {
					delete n.second;
				}
				nodes.clear();
				loaded=false;
			}
			string uid;								//every version of a graph has a UUID, no particular need to actually read its data(?)
													//?? is it faster than using strings??
			string description;
			std::unordered_map<string,Node*> nodes;
			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(xmlIO &XML,const float framerate);
			bool video_render(const string &output_filename,const float framerate,int start, int end);
			bool load(string data,string media_path);
			bool loadFile(string &filename,string media_path);
			bool parseXml(string media_path);
			bool parseJson(string &data,string &media_path);
			bool set_resolution(int w,int h);
			bool preview(xmlIO &XML,string &node,string &format,int frame,int w,int h);
			bool check_audio(string audio,string path);
			bool print_features(xmlIO &XML,string &node);
			bool load_audio(const string &filename,vector<Audio_processor*> processors);
			bool load_video(const string &nodeID,const string &filename);//can be performance or clip
			bool set_bitrate(int b){
				if (b>1000){
					bitRate=b;
					return true;
				}
				else return false;
			}
			bool set_fragmentation(bool f){
				use_fragmentation=f;
				return true;
			}
			bool loaded;
			float duration;
			float framerate;
			const string graphToString();
			xmlIO xml;
			bool audio_loaded;
			string audio_filename;
			bool cancelled;
			float progress;
			int bitRate;

			//Poco::Mutex mutex;     //lock for access from parent thread

			Audio_thumbnailer *audio_thumb;
		private:
			int outW,outH;
			bool use_fragmentation;
			int analysis_seed;

	};
	class Thumbnailer{
		public:
			bool make(const string &inputfilename,int w,int h,const string &outputfilename) {
				//first try svg
				RsvgHandle * rsvg=rsvg_handle_new_from_file(inputfilename.c_str(),nullptr);
				if (rsvg) {
					RsvgDimensionData dims;
					rsvg_handle_get_dimensions(rsvg,&dims);
					cerr<<"Rotor: SVG loaded "<<inputfilename<<" , "<<dims.width<<"x"<<dims.height<<endl;
					cv::Mat cp=cv::Mat::zeros(h,w,CV_8UC4);
					cv::Mat co=cv::Mat(h,w,CV_8UC3);
				    cairo_surface_t * cs = cairo_image_surface_create_for_data (cp.data,
	                                                         CAIRO_FORMAT_RGB24,
	                                                         w,
	                                                         h,
	                                                         w*4);
				    cairo_t * cr = cairo_create (cs);
				    cairo_translate(cr, w/2, h/2);
				    cairo_scale(cr, ((float)w)/640.0f,((float)w)/640.0f);
				    cairo_translate(cr, -w/2, -h/2);
				    cairo_translate(cr, w/2-(dims.width/2), h/2-(dims.height/2));
					rsvg_handle_render_cairo(rsvg,cr);
					cv::cvtColor(cp,co,CV_RGBA2BGR,3);
					cv::imwrite(outputfilename.c_str(),co);
					cairo_destroy(cr);
					cairo_surface_destroy(cs);
					rsvg_handle_close(rsvg,nullptr);
					//g_object_unref(rsvg);
					return true;
				}
				//if not svg feed to FFMS2
				if (player.open(inputfilename)){
					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;
						cvtColor(i.rgb,cp,CV_RGB2BGR);
						cv::imwrite(outputfilename.c_str(),cp);
						return true;
					}
				}
				//fall back to audio
				libav::audio_decoder loader;
				if (loader.open(inputfilename)) {
					Audio_thumbnailer at;
					at.width=w;
					at.height=h;
					int rate = loader.get_sample_rate();
					int samples = loader.get_number_samples();
					int channels= loader.get_number_channels();
					int bits = loader.get_bit_depth();
					at.init(channels,bits,samples,rate);
					uint16_t *audio=new uint16_t[1024*loader.get_number_channels()];
					uint64_t sample=0;
					while (loader.get_samples(audio,sample,1024)) {
						at.process_frame((uint8_t*)audio,1024);
						sample+=1024;
					}
					cv::Mat co=cv::Mat(h,w,CV_8UC3);
					uchar op;
					for (int i=0;i<h;i++){
						uchar* r=co.ptr(i); //pointer to row
						for (int j=0;j<w;j++){
							//audio rms in 0..1 range
							if (at.audiodata[j]>abs(((float)i-h/2)/(h/2))) op=0xFF;
							else op=0x00;
							r[j*3]=op/4;
							r[j*3+1]=op;
							r[j*3+2]=op/4;
						}
					}
					cv::imwrite(outputfilename.c_str(),co);
					return true;
				}
				return false;
			}
		private:
			libav::video_decoder player;
	};
}
#endif