framework2

Форк
0
460 строк · 12.7 Кб
1
/*
2
 * ofGstVideoUtils.cpp
3
 *
4
 *  Created on: 16/01/2011
5
 *      Author: arturo
6
 */
7

8
#include "ofGstVideoPlayer.h"
9
#include <gst/gst.h>
10
#include <gst/video/video.h>
11
#include <gst/app/gstappsink.h>
12
#include "ofConstants.h"
13
#include "ofGstUtils.h"
14

15
ofGstVideoPlayer::ofGstVideoPlayer(){
16
	nFrames						= 0;
17
	internalPixelFormat			= OF_PIXELS_RGB;
18
	bIsStream					= false;
19
	bIsAllocated				= false;
20
	threadAppSink				= false;
21
	bAsyncLoad					= false;
22
	videoUtils.setSinkListener(this);
23
	fps_d = 1;
24
	fps_n = 1;
25
}
26

27
ofGstVideoPlayer::~ofGstVideoPlayer(){
28
	close();
29
}
30

31
bool ofGstVideoPlayer::setPixelFormat(ofPixelFormat pixelFormat){
32
	internalPixelFormat = pixelFormat;
33
	return true;
34
}
35

36
ofPixelFormat ofGstVideoPlayer::getPixelFormat() const {
37
	return internalPixelFormat;
38
}
39

40

41
bool ofGstVideoPlayer::createPipeline(std::string name){
42
#ifndef OF_USE_GST_GL
43
#if GST_VERSION_MAJOR==0
44
	GstCaps *caps;
45
	int bpp;
46
	switch(internalPixelFormat){
47
	case OF_PIXELS_GRAY:
48
		bpp = 8;
49
		caps = gst_caps_new_simple("video/x-raw-gray",
50
			"bpp", G_TYPE_INT, bpp,
51
			"depth", G_TYPE_INT, 8,
52
			NULL);
53
		break;
54
	case OF_PIXELS_RGB:
55
		bpp = 24;
56
		caps = gst_caps_new_simple("video/x-raw-rgb",
57
			"bpp", G_TYPE_INT, bpp,
58
			"depth", G_TYPE_INT, 24,
59
			"endianness",G_TYPE_INT,4321,
60
			"red_mask",G_TYPE_INT,0xff0000,
61
			"green_mask",G_TYPE_INT,0x00ff00,
62
			"blue_mask",G_TYPE_INT,0x0000ff,
63
			NULL);
64
		break;
65
	case OF_PIXELS_RGBA:
66
		bpp = 32;
67
		caps = gst_caps_new_simple("video/x-raw-rgb",
68
			"bpp", G_TYPE_INT, bpp,
69
			"depth", G_TYPE_INT, 32,
70
			"endianness",G_TYPE_INT,4321,
71
			"red_mask",G_TYPE_INT,0xff000000,
72
			"green_mask",G_TYPE_INT,0x00ff0000,
73
			"blue_mask",G_TYPE_INT,0x0000ff00,
74
			"alpha_mask",G_TYPE_INT,0x000000ff,
75
			NULL);
76
		break;
77
	case OF_PIXELS_BGRA:
78
		bpp = 32;
79
		caps = gst_caps_new_simple("video/x-raw-rgb",
80
			"bpp", G_TYPE_INT, bpp,
81
			"depth", G_TYPE_INT, 32,
82
			"endianness",G_TYPE_INT,4321,
83
			"red_mask",G_TYPE_INT,0x0000ff00,
84
			"green_mask",G_TYPE_INT,0x00ff0000,
85
			"blue_mask",G_TYPE_INT,0xff000000,
86
			"alpha_mask",G_TYPE_INT,0x000000ff,
87
			NULL);
88
		break;
89
	default:
90
		bpp = 32;
91
		caps = gst_caps_new_simple("video/x-raw-rgb",
92
			"bpp", G_TYPE_INT, bpp,
93
			"depth", G_TYPE_INT, 24,
94
			"endianness",G_TYPE_INT,4321,
95
			"red_mask",G_TYPE_INT,0xff0000,
96
			"green_mask",G_TYPE_INT,0x00ff00,
97
			"blue_mask",G_TYPE_INT,0x0000ff,
98
			NULL);
99
		break;
100
	}
101
#else
102
	std::string mime="video/x-raw";
103

104
	GstCaps *caps;
105
	if(internalPixelFormat==OF_PIXELS_NATIVE){
106
		caps = gst_caps_from_string((mime + ",format={RGBA,BGRA,RGB,BGR,RGB16,GRAY8,YV12,I420,NV12,NV21,YUY2}").c_str());
107
	}else{
108
		std::string format = ofGstVideoUtils::getGstFormatName(internalPixelFormat);
109
		caps = gst_caps_new_simple(mime.c_str(),
110
											"format", G_TYPE_STRING, format.c_str(),
111
											NULL);
112
	}
113
    
114
#endif
115

116
	#if GST_VERSION_MAJOR==0
117
		GstElement * gstPipeline = gst_element_factory_make("playbin2","player");
118
	#else
119
        #if GST_VERSION_MAJOR==1 && GST_VERSION_MINOR > 18
120
            //TODO: Fedora 35 onwards has issues with playbin - so using playbin3
121
            //TODO: Check future GStreamer versions and potentially return to "playbin", or use a different approach to create the pipeline.
122
            GstElement * gstPipeline = gst_element_factory_make("playbin3","player");
123
        #else
124
            GstElement * gstPipeline = gst_element_factory_make("playbin","player");
125
        #endif
126
    #endif
127
	g_object_ref_sink(gstPipeline);
128
	g_object_set(G_OBJECT(gstPipeline), "uri", name.c_str(), (void*)NULL);
129

130
	// create the oF appsink for video rgb without sync to clock
131
	GstElement * gstSink = gst_element_factory_make("appsink", "app_sink");
132
	gst_app_sink_set_caps(GST_APP_SINK(gstSink), caps);
133
	gst_caps_unref(caps);
134

135
	if(threadAppSink){
136
		GstElement * appQueue = gst_element_factory_make("queue","appsink_queue");
137
		g_object_set(G_OBJECT(appQueue), "leaky", 0, "silent", 1, (void*)NULL);
138
		GstElement* appBin = gst_bin_new("app_bin");
139
		gst_bin_add(GST_BIN(appBin), appQueue);
140
		GstPad* appQueuePad = gst_element_get_static_pad(appQueue, "sink");
141
		GstPad* ghostPad = gst_ghost_pad_new("app_bin_sink", appQueuePad);
142
		gst_object_unref(appQueuePad);
143
		gst_element_add_pad(appBin, ghostPad);
144

145
		gst_bin_add(GST_BIN(appBin), gstSink);
146
		gst_element_link(appQueue, gstSink);
147

148
		g_object_set (G_OBJECT(gstPipeline),"video-sink",appBin,(void*)NULL);
149
	}else{
150
		g_object_set (G_OBJECT(gstPipeline),"video-sink",gstSink,(void*)NULL);
151
	}
152

153
	#ifdef TARGET_WIN32
154
		GstElement *audioSink = gst_element_factory_make("directsoundsink", NULL);
155
		g_object_set (G_OBJECT(gstPipeline),"audio-sink",audioSink,(void*)NULL);
156
	#endif
157

158
	return videoUtils.setPipelineWithSink(gstPipeline,gstSink,bIsStream);
159

160
#else
161
	/*auto gstPipeline = gst_parse_launch(("uridecodebin uri=" + name + " ! glcolorscale name=gl_filter ! appsink name=app_sink").c_str(),NULL);
162
	auto gstSink = gst_bin_get_by_name(GST_BIN(gstPipeline),"app_sink");
163
	auto glfilter = gst_bin_get_by_name(GST_BIN(gstPipeline),"gl_filter");
164
	gst_app_sink_set_caps(GST_APP_SINK(gstSink), caps);
165
	gst_caps_unref(caps);
166

167
	glXMakeCurrent (ofGetX11Display(), None, 0);
168
	glDisplay = (GstGLDisplay *)gst_gl_display_x11_new_with_display(ofGetX11Display());
169
	glContext = gst_gl_context_new_wrapped (glDisplay, (guintptr) ofGetGLXContext(),
170
	    		  GST_GL_PLATFORM_GLX, GST_GL_API_OPENGL);
171

172
	g_object_set (G_OBJECT (glfilter), "other-context", glContext, NULL);
173

174
	// FIXME: this seems to be the way to add the context in 1.4.5
175
	//
176
	// GstBus * bus = gst_pipeline_get_bus (GST_PIPELINE(gstPipeline));
177
	// gst_bus_enable_sync_message_emission (bus);
178
	// g_signal_connect (bus, "sync-message", G_CALLBACK (sync_bus_call), this);
179
	// gst_object_unref(bus);
180

181
	auto ret = videoUtils.setPipelineWithSink(gstPipeline,gstSink,bIsStream);
182
	glXMakeCurrent (ofGetX11Display(), ofGetX11Window(), ofGetGLXContext());
183
	return ret;*/
184

185
	return videoUtils.setPipeline("uridecodebin uri=" + name,internalPixelFormat,bIsStream,-1,-1);
186
	//return videoUtils.setPipeline("filesrc location=" + name + " ! qtdemux ",internalPixelFormat,bIsStream,-1,-1);
187
#endif
188
}
189

190
void ofGstVideoPlayer::loadAsync(std::string name){
191
	bAsyncLoad = true;
192
	load(name);
193
}
194

195
bool ofGstVideoPlayer::load(std::string name){
196
	if( name.find( "file://",0 ) != std::string::npos){
197
		bIsStream = bAsyncLoad;
198
	}else if( name.find( "://",0 ) == std::string::npos){
199
		GError * err = NULL;
200
		gchar* name_ptr = gst_filename_to_uri(ofToDataPath(name).c_str(),&err);
201
		name = name_ptr;
202
		g_free(name_ptr);
203
		if(err) g_free(err);
204
		//name = ofToDataPath(name);
205
		bIsStream = bAsyncLoad;
206
	}else{
207
		bIsStream = true;
208
	}
209
	ofLogVerbose("ofGstVideoPlayer") << "loadMovie(): loading \"" << name << "\"";
210

211
	if(isInitialized()){
212
		gst_element_set_state (videoUtils.getPipeline(), GST_STATE_READY);
213
		if(!bIsStream){
214
			gst_element_get_state (videoUtils.getPipeline(), NULL, NULL, -1);
215
		}
216
		internalPixelFormat = OF_PIXELS_NATIVE;
217
		bIsAllocated = false;
218
		videoUtils.reallocateOnNextFrame();
219
		g_object_set(G_OBJECT(videoUtils.getPipeline()), "uri", name.c_str(), (void*)NULL);
220
		gst_element_set_state (videoUtils.getPipeline(), GST_STATE_PAUSED);
221
		if(!bIsStream){
222
			gst_element_get_state (videoUtils.getPipeline(), NULL, NULL, -1);
223
			return allocate();
224
		}else{
225
			return true;
226
		}
227
	}else{
228
		ofGstUtils::startGstMainLoop();
229
		return createPipeline(name) &&
230
				videoUtils.startPipeline() &&
231
				(bIsStream || allocate());
232
	}
233
}
234

235
void ofGstVideoPlayer::setThreadAppSink(bool threaded){
236
	threadAppSink = threaded;
237
}
238

239

240
bool ofGstVideoPlayer::allocate(){
241
	if(bIsAllocated){
242
		return true;
243
	}
244

245
	guint64 durationNanos = videoUtils.getDurationNanos();
246

247
	nFrames		  = 0;
248
	if(GstPad* pad = gst_element_get_static_pad(videoUtils.getSink(), "sink")){
249
#if GST_VERSION_MAJOR==0
250
		int width,height;
251
		if(gst_video_get_size(GST_PAD(pad), &width, &height)){
252
			if(!videoUtils.allocate(width,height,internalPixelFormat)) return false;
253
		}else{
254
			ofLogError("ofGstVideoPlayer") << "allocate(): couldn't query width and height";
255
			return false;
256
		}
257

258
		const GValue *framerate = gst_video_frame_rate(pad);
259
		fps_n=0;
260
		fps_d=0;
261
		if(framerate && GST_VALUE_HOLDS_FRACTION (framerate)){
262
			fps_n = gst_value_get_fraction_numerator (framerate);
263
			fps_d = gst_value_get_fraction_denominator (framerate);
264
			nFrames = (float)(durationNanos / (float)GST_SECOND) * (float)fps_n/(float)fps_d;
265
			ofLogVerbose("ofGstVideoPlayer") << "allocate(): framerate: " << fps_n << "/" << fps_d;
266
		}else{
267
			ofLogWarning("ofGstVideoPlayer") << "allocate(): cannot get framerate, frame seek won't work";
268
		}
269
		bIsAllocated = true;
270
#else
271
		if(GstCaps *caps = gst_pad_get_current_caps (GST_PAD (pad))){
272
			GstVideoInfo info;
273
			gst_video_info_init (&info);
274
			if (gst_video_info_from_caps (&info, caps)){
275
				ofPixelFormat format = ofGstVideoUtils::getOFFormat(GST_VIDEO_INFO_FORMAT(&info));
276
				if(format!=internalPixelFormat){
277
					ofLogVerbose("ofGstVideoPlayer") << "allocating as " << info.width << "x" << info.height << " " << info.finfo->description << " " << info.finfo->name;
278
					internalPixelFormat = format;
279
				}
280
				if(!videoUtils.allocate(info.width,info.height,format)) return false;
281
			}else{
282
				ofLogError("ofGstVideoPlayer") << "allocate(): couldn't query width and height";
283
				return false;
284
			}
285

286
			fps_n = info.fps_n;
287
			fps_d = info.fps_d;
288
			nFrames = (float)(durationNanos / (float)GST_SECOND) * (float)fps_n/(float)fps_d;
289
			gst_caps_unref(caps);
290
			bIsAllocated = true;
291
		}else{
292
			ofLogError("ofGstVideoPlayer") << "allocate(): cannot get pipeline caps";
293
			bIsAllocated = false;
294
		}
295
#endif
296
		gst_object_unref(GST_OBJECT(pad));
297
	}else{
298
		ofLogError("ofGstVideoPlayer") << "allocate(): cannot get sink pad";
299
		bIsAllocated = false;
300
	}
301
	return bIsAllocated;
302
}
303

304
void ofGstVideoPlayer::on_stream_prepared(){
305
	if(!bIsAllocated) allocate();
306
}
307

308
int	ofGstVideoPlayer::getCurrentFrame() const {
309
	int frame = 0;
310

311
	// zach I think this may fail on variable length frames...
312
	float pos = getPosition();
313
	if(pos == -1) return -1;
314

315

316
	float  framePosInFloat = ((float)getTotalNumFrames() * pos);
317
	int    framePosInInt = (int)framePosInFloat;
318
	float  floatRemainder = (framePosInFloat - framePosInInt);
319
	if (floatRemainder > 0.5f) framePosInInt = framePosInInt + 1;
320
	//frame = (int)ceil((getTotalNumFrames() * getPosition()));
321
	frame = framePosInInt;
322

323
	return frame;
324
}
325

326
int	ofGstVideoPlayer::getTotalNumFrames() const {
327
	return nFrames;
328
}
329

330
void ofGstVideoPlayer::firstFrame(){
331
	setFrame(0);
332
}
333

334
void ofGstVideoPlayer::nextFrame(){
335
	gint64 currentFrame = getCurrentFrame();
336
	if(currentFrame!=-1) setFrame(currentFrame + 1);
337
}
338

339
void ofGstVideoPlayer::previousFrame(){
340
	gint64 currentFrame = getCurrentFrame();
341
	if(currentFrame!=-1) setFrame(currentFrame - 1);
342
}
343

344
void ofGstVideoPlayer::setFrame(int frame){ // frame 0 = first frame...
345
	float pct = (float)frame / (float)nFrames;
346
	setPosition(pct);
347
}
348

349
bool ofGstVideoPlayer::isStream() const {
350
	return bIsStream;
351
}
352

353
void ofGstVideoPlayer::update(){
354
	videoUtils.update();
355
}
356

357
void ofGstVideoPlayer::play(){
358
	videoUtils.play();
359
}
360

361
void ofGstVideoPlayer::stop(){
362
	videoUtils.stop();
363
}
364

365
void ofGstVideoPlayer::setPaused(bool bPause){
366
	videoUtils.setPaused(bPause);
367
}
368

369
bool ofGstVideoPlayer::isPaused() const {
370
	return videoUtils.isPaused();
371
}
372

373
bool ofGstVideoPlayer::isLoaded() const {
374
	return videoUtils.isLoaded();
375
}
376

377
bool ofGstVideoPlayer::isPlaying() const {
378
	return videoUtils.isPlaying();
379
}
380

381
float ofGstVideoPlayer::getPosition() const {
382
	return videoUtils.getPosition();
383
}
384

385
float ofGstVideoPlayer::getSpeed() const {
386
	return videoUtils.getSpeed();
387
}
388

389
float ofGstVideoPlayer::getDuration() const {
390
	return videoUtils.getDuration();
391
}
392

393
bool ofGstVideoPlayer::getIsMovieDone() const {
394
	return videoUtils.getIsMovieDone();
395
}
396

397
void ofGstVideoPlayer::setPosition(float pct){
398
	videoUtils.setPosition(pct);
399
}
400

401
void ofGstVideoPlayer::setVolume(float volume){
402
	videoUtils.setVolume(volume);
403
}
404

405
void ofGstVideoPlayer::setLoopState(ofLoopType state){
406
	videoUtils.setLoopState(state);
407
}
408

409
ofLoopType ofGstVideoPlayer::getLoopState() const {
410
	return videoUtils.getLoopState();
411
}
412

413
void ofGstVideoPlayer::setSpeed(float speed){
414
	videoUtils.setSpeed(speed);
415
}
416

417
void ofGstVideoPlayer::close(){
418
	bIsAllocated = false;
419
	videoUtils.close();
420
}
421

422
bool ofGstVideoPlayer::isFrameNew() const {
423
	return videoUtils.isFrameNew();
424
}
425

426
ofPixels& ofGstVideoPlayer::getPixels(){
427
	return videoUtils.getPixels();
428
}
429

430
const ofPixels& ofGstVideoPlayer::getPixels() const {
431
	return videoUtils.getPixels();
432
}
433

434
ofTexture * ofGstVideoPlayer::getTexturePtr(){
435
	return videoUtils.getTexture();
436
}
437

438
float ofGstVideoPlayer::getHeight() const {
439
	return videoUtils.getHeight();
440
}
441

442
float ofGstVideoPlayer::getWidth() const {
443
	return videoUtils.getWidth();
444
}
445

446
ofGstVideoUtils * ofGstVideoPlayer::getGstVideoUtils(){
447
	return &videoUtils;
448
}
449

450
void ofGstVideoPlayer::setFrameByFrame(bool frameByFrame){
451
	videoUtils.setFrameByFrame(frameByFrame);
452
}
453

454
bool ofGstVideoPlayer::isThreadedAppSink() const{
455
	return threadAppSink;
456
}
457

458
bool ofGstVideoPlayer::isFrameByFrame() const{
459
	return videoUtils.isFrameByFrame();
460
}
461

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.