1 /*************************************************************************/
2 /*  video_stream_gdnative.h                                              */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 
31 #ifndef VIDEO_STREAM_GDNATIVE_H
32 #define VIDEO_STREAM_GDNATIVE_H
33 
34 #include "../gdnative.h"
35 #include "core/os/file_access.h"
36 #include "scene/resources/texture.h"
37 #include "scene/resources/video_stream.h"
38 
39 struct VideoDecoderGDNative {
40 	const godot_videodecoder_interface_gdnative *interface;
41 	String plugin_name;
42 	Vector<String> supported_extensions;
43 
VideoDecoderGDNativeVideoDecoderGDNative44 	VideoDecoderGDNative() :
45 			interface(NULL),
46 			plugin_name("none") {}
47 
VideoDecoderGDNativeVideoDecoderGDNative48 	VideoDecoderGDNative(const godot_videodecoder_interface_gdnative *p_interface) :
49 			interface(p_interface),
50 			plugin_name(p_interface->get_plugin_name()) {
51 		_get_supported_extensions();
52 	}
53 
54 private:
_get_supported_extensionsVideoDecoderGDNative55 	void _get_supported_extensions() {
56 		supported_extensions.clear();
57 		int num_ext;
58 		const char **supported_ext = interface->get_supported_extensions(&num_ext);
59 		for (int i = 0; i < num_ext; i++) {
60 			supported_extensions.push_back(supported_ext[i]);
61 		}
62 	}
63 };
64 
65 class VideoDecoderServer {
66 private:
67 	Vector<VideoDecoderGDNative *> decoders;
68 	Map<String, int> extensions;
69 
70 	static VideoDecoderServer *instance;
71 
72 public:
get_instance()73 	static VideoDecoderServer *get_instance() {
74 		return instance;
75 	}
76 
get_extensions()77 	const Map<String, int> &get_extensions() {
78 		return extensions;
79 	}
80 
register_decoder_interface(const godot_videodecoder_interface_gdnative * p_interface)81 	void register_decoder_interface(const godot_videodecoder_interface_gdnative *p_interface) {
82 		VideoDecoderGDNative *decoder = memnew(VideoDecoderGDNative(p_interface));
83 		int index = decoders.size();
84 		for (int i = 0; i < decoder->supported_extensions.size(); i++) {
85 			extensions[decoder->supported_extensions[i]] = index;
86 		}
87 		decoders.push_back(decoder);
88 	}
89 
get_decoder(const String & extension)90 	VideoDecoderGDNative *get_decoder(const String &extension) {
91 		if (extensions.size() == 0 || !extensions.has(extension))
92 			return NULL;
93 		return decoders[extensions[extension]];
94 	}
95 
VideoDecoderServer()96 	VideoDecoderServer() {
97 		instance = this;
98 	}
99 
~VideoDecoderServer()100 	~VideoDecoderServer() {
101 		for (int i = 0; i < decoders.size(); i++) {
102 			memdelete(decoders[i]);
103 		}
104 		decoders.clear();
105 		instance = NULL;
106 	}
107 };
108 
109 class VideoStreamPlaybackGDNative : public VideoStreamPlayback {
110 
111 	GDCLASS(VideoStreamPlaybackGDNative, VideoStreamPlayback);
112 
113 	Ref<ImageTexture> texture;
114 	bool playing;
115 	bool paused;
116 
117 	Vector2 texture_size;
118 
119 	void *mix_udata;
120 	AudioMixCallback mix_callback;
121 
122 	int num_channels;
123 	float time;
124 	bool seek_backward;
125 	int mix_rate;
126 	double delay_compensation;
127 
128 	float *pcm;
129 	int pcm_write_idx;
130 	int samples_decoded;
131 
132 	void cleanup();
133 	void update_texture();
134 
135 protected:
136 	String file_name;
137 
138 	FileAccess *file;
139 
140 	const godot_videodecoder_interface_gdnative *interface;
141 	void *data_struct;
142 
143 public:
144 	VideoStreamPlaybackGDNative();
145 	~VideoStreamPlaybackGDNative();
146 
147 	void set_interface(const godot_videodecoder_interface_gdnative *p_interface);
148 
149 	bool open_file(const String &p_file);
150 
151 	virtual void stop();
152 	virtual void play();
153 
154 	virtual bool is_playing() const;
155 
156 	virtual void set_paused(bool p_paused);
157 	virtual bool is_paused() const;
158 
159 	virtual void set_loop(bool p_enable);
160 	virtual bool has_loop() const;
161 
162 	virtual float get_length() const;
163 
164 	virtual float get_playback_position() const;
165 	virtual void seek(float p_time);
166 
167 	virtual void set_audio_track(int p_idx);
168 
169 	//virtual int mix(int16_t* p_buffer,int p_frames)=0;
170 
171 	virtual Ref<Texture> get_texture() const;
172 	virtual void update(float p_delta);
173 
174 	virtual void set_mix_callback(AudioMixCallback p_callback, void *p_userdata);
175 	virtual int get_channels() const;
176 	virtual int get_mix_rate() const;
177 };
178 
179 class VideoStreamGDNative : public VideoStream {
180 
181 	GDCLASS(VideoStreamGDNative, VideoStream);
182 
183 	String file;
184 	int audio_track;
185 
186 protected:
187 	static void
188 	_bind_methods();
189 
190 public:
191 	void set_file(const String &p_file);
192 	String get_file();
193 
194 	virtual void set_audio_track(int p_track);
195 	virtual Ref<VideoStreamPlayback> instance_playback();
196 
VideoStreamGDNative()197 	VideoStreamGDNative() {}
198 };
199 
200 class ResourceFormatLoaderVideoStreamGDNative : public ResourceFormatLoader {
201 public:
202 	virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
203 	virtual void get_recognized_extensions(List<String> *p_extensions) const;
204 	virtual bool handles_type(const String &p_type) const;
205 	virtual String get_resource_type(const String &p_path) const;
206 };
207 
208 #endif
209