├── .gitignore ├── AUTHORS ├── COPYING ├── Makefile.am ├── NEWS ├── README ├── README.md ├── android ├── .gitignore ├── Makefile.am ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── org │ │ │ └── freedesktop │ │ │ └── gstreamer │ │ │ ├── Player.java │ │ │ └── player │ │ │ ├── GStreamerSurfaceView.java │ │ │ └── Play.java │ │ ├── jni │ │ ├── Android.mk │ │ ├── Application.mk │ │ └── player.c │ │ └── res │ │ ├── layout │ │ └── main.xml │ │ └── values │ │ └── strings.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── autogen.sh ├── configure.ac ├── gst-play ├── Makefile.am ├── gst-play-kb.c ├── gst-play-kb.h └── gst-play.c ├── gtk ├── Makefile.am ├── gtk-play.c ├── gtk-video-renderer.c ├── gtk-video-renderer.h └── resources │ ├── gresources.xml │ ├── media_info_dialog.ui │ ├── toolbar.css │ └── toolbar.ui ├── ios ├── GstPlay.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcuserdata │ │ └── slomo.xcuserdatad │ │ └── xcschemes │ │ ├── GstPlay.xcscheme │ │ └── xcschememanagement.plist ├── GstPlay │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── EaglUIVIew.h │ ├── EaglUIVIew.m │ ├── GstPlay-Info.plist │ ├── GstPlay-Prefix.pch │ ├── LibraryViewController.h │ ├── LibraryViewController.m │ ├── MainStoryboard_iPad.storyboard │ ├── MainStoryboard_iPhone.storyboard │ ├── OnlineMedia.plist │ ├── Ubuntu-R.ttf │ ├── VideoViewController.h │ ├── VideoViewController.m │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── fonts.conf │ ├── gst_ios_init.h │ ├── gst_ios_init.m │ └── main.m └── Makefile.am ├── qt ├── deployment.pri ├── fontawesome-webfont.ttf ├── fontawesome-webfont.ttf.txt ├── fontawesome.js ├── imagesample.cpp ├── imagesample.h ├── main.cpp ├── main.qml ├── play.pro ├── player.cpp ├── player.h ├── qgstplayer.cpp ├── qgstplayer.h ├── qml.qrc ├── quickrenderer.cpp └── quickrenderer.h └── win32 ├── gst-play ├── gst-play.vcxproj └── gst-play.vcxproj.filters └── gst-player.sln /.gitignore: -------------------------------------------------------------------------------- 1 | m4/ 2 | autom4te.cache/ 3 | aclocal.m4 4 | config.guess 5 | config.h 6 | config.h.in 7 | config.log 8 | config.sub 9 | config.status 10 | configure 11 | compile 12 | stamp-h1 13 | libtool 14 | test-driver 15 | depcomp 16 | install-sh 17 | missing 18 | ltmain.sh 19 | INSTALL 20 | ChangeLog 21 | 22 | android/assets 23 | android/bin 24 | android/gen 25 | android/gst-build* 26 | android/libs 27 | android/obj 28 | android/local.properties 29 | android/project.properties 30 | android/proguard-project.txt 31 | android/src/org/freedesktop/gstreamer/GStreamer.java 32 | 33 | gst-play/gst-play 34 | gtk/gtk-play 35 | gtk/gtk-play-resources.c 36 | gtk/gtk-play-resources.h 37 | 38 | docs/**/*.stamp 39 | docs/*/*-decl-list.txt 40 | docs/*/*-decl.txt 41 | docs/*/*-overrides.txt 42 | docs/*/*-undeclared.txt 43 | docs/*/*-undocumented.txt 44 | docs/*/*-unused.txt 45 | docs/*/*.args 46 | docs/*/*.hierarchy 47 | docs/*/*.interfaces 48 | docs/*/*.prerequisites 49 | docs/*/*.signals 50 | docs/*/tmpl 51 | docs/*/xml 52 | docs/*/html 53 | 54 | pkgconfig/*.pc 55 | 56 | *~ 57 | *.gir 58 | *.typelib 59 | *.swp 60 | *.log 61 | *.trs 62 | *.o 63 | *.lo 64 | *.la 65 | .deps 66 | .libs 67 | 68 | **/Makefile 69 | **/Makefile.in 70 | **/xcuserdata/ 71 | **/xcshareddata/ 72 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdroege/gst-player/ee3c226c82767a089743e4e06058743e67f73cdb/AUTHORS -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | if HAVE_GTK 2 | gtk_dir = gtk 3 | endif 4 | 5 | SUBDIRS = gst-play $(gtk_dir) 6 | DIST_SUBDIRS = android gst-play gtk ios 7 | 8 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdroege/gst-player/ee3c226c82767a089743e4e06058743e67f73cdb/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdroege/gst-player/ee3c226c82767a089743e4e06058743e67f73cdb/README -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gst-player 2 | GStreamer Playback API 3 | 4 | This repository only exists for historical reasons. GstPlayer is part of GStreamer since 1.8.0 and the example applications can now be found here: 5 | https://cgit.freedesktop.org/gstreamer/gst-examples 6 | 7 | Bugs or feature requests should be posted here: 8 | https://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer 9 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | 10 | .idea 11 | gradlew 12 | gradlew.bat 13 | gradle/ 14 | -------------------------------------------------------------------------------- /android/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = \ 2 | build.gradle \ 3 | gradle.properties \ 4 | settings.gradle \ 5 | app/build.gradle \ 6 | app/proguard-rules.pro \ 7 | app/src/main/AndroidManifest.xml \ 8 | app/src/main/java/org/freedesktop/gstreamer/Player.java \ 9 | app/src/main/java/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java \ 10 | app/src/main/java/org/freedesktop/gstreamer/player/Play.java \ 11 | app/src/main/jni/Android.mk \ 12 | app/src/main/jni/Application.mk \ 13 | app/src/main/jni/player.c \ 14 | app/src/main/res/layout/main.xml \ 15 | app/src/main/res/values/strings.xml 16 | -------------------------------------------------------------------------------- /android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | src/main/java/org/freedesktop/gstreamer/GStreamer.java 3 | assets/ 4 | gst-build-armeabi/ 5 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | 4 | def getNdkCommandLine(ndkRoot, target) { 5 | def gstRoot 6 | 7 | if (project.hasProperty('gstAndroidRoot')) 8 | gstRoot = project.gstAndroidRoot 9 | else 10 | gstRoot = System.properties['user.home'] + '/cerbero/dist/android_arm' 11 | 12 | if (ndkRoot == null) 13 | throw new GradleException('NDK not configured') 14 | 15 | return ["$ndkRoot/ndk-build", 16 | 'NDK_PROJECT_PATH=build', 17 | 'APP_BUILD_SCRIPT=src/main/jni/Android.mk', 18 | 'NDK_APPLICATION_MK=src/main/jni/Application.mk', 19 | 'GSTREAMER_JAVA_SRC_DIR=src/main/java', 20 | "GSTREAMER_ROOT_ANDROID=$gstRoot", 21 | target] 22 | } 23 | 24 | android { 25 | compileSdkVersion 23 26 | buildToolsVersion "23.0.3" 27 | 28 | sourceSets { 29 | main { 30 | // Avoid using the built in JNI generation plugin 31 | jni.srcDirs = [] 32 | jniLibs.srcDirs = ['build/libs'] 33 | } 34 | } 35 | 36 | defaultConfig { 37 | applicationId "org.freedesktop.gstreamer.play" 38 | minSdkVersion 15 39 | targetSdkVersion 15 40 | versionCode 1 41 | versionName "1.0" 42 | } 43 | 44 | buildTypes { 45 | release { 46 | minifyEnabled false 47 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 48 | } 49 | } 50 | 51 | // Before compiling our app, prepare NDK code 52 | tasks.withType(JavaCompile) { 53 | compileTask -> compileTask.dependsOn ndkBuild 54 | } 55 | 56 | // Need to call clean on NDK ourselves too 57 | clean.dependsOn 'ndkClean' 58 | 59 | // Build native code using mk files like on Eclipse 60 | task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') { 61 | commandLine getNdkCommandLine(android.ndkDirectory, 'all') 62 | } 63 | 64 | task ndkClean(type: Exec, description: 'Clean JNI code built via NDK') { 65 | commandLine getNdkCommandLine(android.ndkDirectory, 'clean') 66 | } 67 | } 68 | 69 | afterEvaluate { 70 | compileDebugJavaWithJavac.dependsOn 'externalNativeBuildDebug' 71 | compileReleaseJavaWithJavac.dependsOn 'externalNativeBuildRelease' 72 | } 73 | 74 | dependencies { 75 | compile fileTree(dir: 'libs', include: ['*.jar']) 76 | testCompile 'junit:junit:4.12' 77 | compile 'com.android.support:appcompat-v7:23.1.1' 78 | } 79 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/arun/code/android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /android/app/src/main/java/org/freedesktop/gstreamer/Player.java: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2014-2015 Sebastian Dröge 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | package org.freedesktop.gstreamer; 22 | 23 | import java.io.Closeable; 24 | import android.view.Surface; 25 | import android.content.Context; 26 | import org.freedesktop.gstreamer.GStreamer; 27 | 28 | public class Player implements Closeable { 29 | private static native void nativeClassInit(); 30 | public static void init(Context context) throws Exception { 31 | System.loadLibrary("gstreamer_android"); 32 | GStreamer.init(context); 33 | 34 | System.loadLibrary("gstplayer"); 35 | nativeClassInit(); 36 | } 37 | 38 | private long native_player; 39 | private native void nativeNew(); 40 | public Player() { 41 | nativeNew(); 42 | } 43 | 44 | private native void nativeFree(); 45 | @Override 46 | public void close() { 47 | nativeFree(); 48 | } 49 | 50 | private native void nativePlay(); 51 | public void play() { 52 | nativePlay(); 53 | } 54 | 55 | private native void nativePause(); 56 | public void pause() { 57 | nativePause(); 58 | } 59 | 60 | private native void nativeStop(); 61 | public void stop() { 62 | nativeStop(); 63 | } 64 | 65 | private native void nativeSeek(long position); 66 | public void seek(long position) { 67 | nativeSeek(position); 68 | } 69 | 70 | private native String nativeGetUri(); 71 | public String getUri() { 72 | return nativeGetUri(); 73 | } 74 | 75 | private native void nativeSetUri(String uri); 76 | public void setUri(String uri) { 77 | nativeSetUri(uri); 78 | } 79 | 80 | private native long nativeGetPosition(); 81 | public long getPosition() { 82 | return nativeGetPosition(); 83 | } 84 | 85 | private native long nativeGetDuration(); 86 | public long getDuration() { 87 | return nativeGetDuration(); 88 | } 89 | 90 | private native double nativeGetVolume(); 91 | public double getVolume() { 92 | return nativeGetVolume(); 93 | } 94 | 95 | private native void nativeSetVolume(double volume); 96 | public void setVolume(double volume) { 97 | nativeSetVolume(volume); 98 | } 99 | 100 | private native boolean nativeGetMute(); 101 | public boolean getMute() { 102 | return nativeGetMute(); 103 | } 104 | 105 | private native void nativeSetMute(boolean mute); 106 | public void setMute(boolean mute) { 107 | nativeSetMute(mute); 108 | } 109 | 110 | private Surface surface; 111 | private native void nativeSetSurface(Surface surface); 112 | public void setSurface(Surface surface) { 113 | this.surface = surface; 114 | nativeSetSurface(surface); 115 | } 116 | 117 | public Surface getSurface() { 118 | return surface; 119 | } 120 | 121 | public static interface PositionUpdatedListener { 122 | abstract void positionUpdated(Player player, long position); 123 | } 124 | 125 | private PositionUpdatedListener positionUpdatedListener; 126 | public void setPositionUpdatedListener(PositionUpdatedListener listener) { 127 | positionUpdatedListener = listener; 128 | } 129 | 130 | private void onPositionUpdated(long position) { 131 | if (positionUpdatedListener != null) { 132 | positionUpdatedListener.positionUpdated(this, position); 133 | } 134 | } 135 | 136 | public static interface DurationChangedListener { 137 | abstract void durationChanged(Player player, long duration); 138 | } 139 | 140 | private DurationChangedListener durationChangedListener; 141 | public void setDurationChangedListener(DurationChangedListener listener) { 142 | durationChangedListener = listener; 143 | } 144 | 145 | private void onDurationChanged(long duration) { 146 | if (durationChangedListener != null) { 147 | durationChangedListener.durationChanged(this, duration); 148 | } 149 | } 150 | 151 | private static final State[] stateMap = {State.STOPPED, State.BUFFERING, State.PAUSED, State.PLAYING}; 152 | public enum State { 153 | STOPPED, 154 | BUFFERING, 155 | PAUSED, 156 | PLAYING 157 | } 158 | 159 | public static interface StateChangedListener { 160 | abstract void stateChanged(Player player, State state); 161 | } 162 | 163 | private StateChangedListener stateChangedListener; 164 | public void setStateChangedListener(StateChangedListener listener) { 165 | stateChangedListener = listener; 166 | } 167 | 168 | private void onStateChanged(int stateIdx) { 169 | if (stateChangedListener != null) { 170 | State state = stateMap[stateIdx]; 171 | stateChangedListener.stateChanged(this, state); 172 | } 173 | } 174 | 175 | public static interface BufferingListener { 176 | abstract void buffering(Player player, int percent); 177 | } 178 | 179 | private BufferingListener bufferingListener; 180 | public void setBufferingListener(BufferingListener listener) { 181 | bufferingListener = listener; 182 | } 183 | 184 | private void onBuffering(int percent) { 185 | if (bufferingListener != null) { 186 | bufferingListener.buffering(this, percent); 187 | } 188 | } 189 | 190 | public static interface EndOfStreamListener { 191 | abstract void endOfStream(Player player); 192 | } 193 | 194 | private EndOfStreamListener endOfStreamListener; 195 | public void setEndOfStreamListener(EndOfStreamListener listener) { 196 | endOfStreamListener = listener; 197 | } 198 | 199 | private void onEndOfStream() { 200 | if (endOfStreamListener != null) { 201 | endOfStreamListener.endOfStream(this); 202 | } 203 | } 204 | 205 | // Keep these in sync with gstplayer.h 206 | private static final Error[] errorMap = {Error.FAILED}; 207 | public enum Error { 208 | FAILED 209 | } 210 | 211 | public static interface ErrorListener { 212 | abstract void error(Player player, Error error, String errorMessage); 213 | } 214 | 215 | private ErrorListener errorListener; 216 | public void setErrorListener(ErrorListener listener) { 217 | errorListener = listener; 218 | } 219 | 220 | private void onError(int errorCode, String errorMessage) { 221 | if (errorListener != null) { 222 | Error error = errorMap[errorCode]; 223 | errorListener.error(this, error, errorMessage); 224 | } 225 | } 226 | 227 | public static interface VideoDimensionsChangedListener { 228 | abstract void videoDimensionsChanged(Player player, int width, int height); 229 | } 230 | 231 | private VideoDimensionsChangedListener videoDimensionsChangedListener; 232 | public void setVideoDimensionsChangedListener(VideoDimensionsChangedListener listener) { 233 | videoDimensionsChangedListener = listener; 234 | } 235 | 236 | private void onVideoDimensionsChanged(int width, int height) { 237 | if (videoDimensionsChangedListener != null) { 238 | videoDimensionsChangedListener.videoDimensionsChanged(this, width, height); 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /android/app/src/main/java/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2014 Sebastian Dröge 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | package org.freedesktop.gstreamer.play; 22 | 23 | import android.content.Context; 24 | import android.util.AttributeSet; 25 | import android.util.Log; 26 | import android.view.SurfaceView; 27 | import android.view.View; 28 | 29 | // A simple SurfaceView whose width and height can be set from the outside 30 | public class GStreamerSurfaceView extends SurfaceView { 31 | public int media_width = 320; 32 | public int media_height = 240; 33 | 34 | // Mandatory constructors, they do not do much 35 | public GStreamerSurfaceView(Context context, AttributeSet attrs, 36 | int defStyle) { 37 | super(context, attrs, defStyle); 38 | } 39 | 40 | public GStreamerSurfaceView(Context context, AttributeSet attrs) { 41 | super(context, attrs); 42 | } 43 | 44 | public GStreamerSurfaceView (Context context) { 45 | super(context); 46 | } 47 | 48 | // Called by the layout manager to find out our size and give us some rules. 49 | // We will try to maximize our size, and preserve the media's aspect ratio if 50 | // we are given the freedom to do so. 51 | @Override 52 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 53 | if (media_width == 0 || media_height == 0) { 54 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 55 | return; 56 | } 57 | 58 | int width = 0, height = 0; 59 | int wmode = View.MeasureSpec.getMode(widthMeasureSpec); 60 | int hmode = View.MeasureSpec.getMode(heightMeasureSpec); 61 | int wsize = View.MeasureSpec.getSize(widthMeasureSpec); 62 | int hsize = View.MeasureSpec.getSize(heightMeasureSpec); 63 | 64 | Log.i ("GStreamer", "onMeasure called with " + media_width + "x" + media_height); 65 | // Obey width rules 66 | switch (wmode) { 67 | case View.MeasureSpec.AT_MOST: 68 | if (hmode == View.MeasureSpec.EXACTLY) { 69 | width = Math.min(hsize * media_width / media_height, wsize); 70 | break; 71 | } 72 | case View.MeasureSpec.EXACTLY: 73 | width = wsize; 74 | break; 75 | case View.MeasureSpec.UNSPECIFIED: 76 | width = media_width; 77 | } 78 | 79 | // Obey height rules 80 | switch (hmode) { 81 | case View.MeasureSpec.AT_MOST: 82 | if (wmode == View.MeasureSpec.EXACTLY) { 83 | height = Math.min(wsize * media_height / media_width, hsize); 84 | break; 85 | } 86 | case View.MeasureSpec.EXACTLY: 87 | height = hsize; 88 | break; 89 | case View.MeasureSpec.UNSPECIFIED: 90 | height = media_height; 91 | } 92 | 93 | // Finally, calculate best size when both axis are free 94 | if (hmode == View.MeasureSpec.AT_MOST && wmode == View.MeasureSpec.AT_MOST) { 95 | int correct_height = width * media_height / media_width; 96 | int correct_width = height * media_width / media_height; 97 | 98 | if (correct_height < height) 99 | height = correct_height; 100 | else 101 | width = correct_width; 102 | } 103 | 104 | // Obey minimum size 105 | width = Math.max (getSuggestedMinimumWidth(), width); 106 | height = Math.max (getSuggestedMinimumHeight(), height); 107 | setMeasuredDimension(width, height); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /android/app/src/main/java/org/freedesktop/gstreamer/player/Play.java: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2014 Sebastian Dröge 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | package org.freedesktop.gstreamer.play; 22 | 23 | import java.text.SimpleDateFormat; 24 | import java.util.Date; 25 | import java.util.TimeZone; 26 | 27 | import android.app.Activity; 28 | import android.content.Context; 29 | import android.content.Intent; 30 | import android.os.Bundle; 31 | import android.os.PowerManager; 32 | import android.util.Log; 33 | import android.view.SurfaceHolder; 34 | import android.view.SurfaceView; 35 | import android.view.View; 36 | import android.view.View.OnClickListener; 37 | import android.widget.ImageButton; 38 | import android.widget.SeekBar; 39 | import android.widget.SeekBar.OnSeekBarChangeListener; 40 | import android.widget.TextView; 41 | import android.widget.Toast; 42 | 43 | import org.freedesktop.gstreamer.Player; 44 | 45 | public class Play extends Activity implements SurfaceHolder.Callback, OnSeekBarChangeListener { 46 | private PowerManager.WakeLock wake_lock; 47 | private Player player; 48 | 49 | @Override 50 | public void onCreate(Bundle savedInstanceState) 51 | { 52 | super.onCreate(savedInstanceState); 53 | 54 | try { 55 | Player.init(this); 56 | } catch (Exception e) { 57 | Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); 58 | finish(); 59 | return; 60 | } 61 | 62 | setContentView(R.layout.main); 63 | 64 | player = new Player(); 65 | 66 | PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 67 | wake_lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GStreamer Play"); 68 | wake_lock.setReferenceCounted(false); 69 | 70 | ImageButton play = (ImageButton) this.findViewById(R.id.button_play); 71 | play.setOnClickListener(new OnClickListener() { 72 | public void onClick(View v) { 73 | player.play(); 74 | wake_lock.acquire(); 75 | } 76 | }); 77 | 78 | ImageButton pause = (ImageButton) this.findViewById(R.id.button_pause); 79 | pause.setOnClickListener(new OnClickListener() { 80 | public void onClick(View v) { 81 | player.pause(); 82 | wake_lock.release(); 83 | } 84 | }); 85 | 86 | final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); 87 | sb.setOnSeekBarChangeListener(this); 88 | 89 | player.setPositionUpdatedListener(new Player.PositionUpdatedListener() { 90 | public void positionUpdated(Player player, final long position) { 91 | runOnUiThread (new Runnable() { 92 | public void run() { 93 | sb.setProgress((int) (position / 1000000)); 94 | updateTimeWidget(); 95 | } 96 | }); 97 | } 98 | }); 99 | 100 | player.setDurationChangedListener(new Player.DurationChangedListener() { 101 | public void durationChanged(Player player, final long duration) { 102 | runOnUiThread (new Runnable() { 103 | public void run() { 104 | sb.setMax((int) (duration / 1000000)); 105 | updateTimeWidget(); 106 | } 107 | }); 108 | } 109 | }); 110 | 111 | final GStreamerSurfaceView gsv = (GStreamerSurfaceView) this.findViewById(R.id.surface_video); 112 | player.setVideoDimensionsChangedListener(new Player.VideoDimensionsChangedListener() { 113 | public void videoDimensionsChanged(Player player, final int width, final int height) { 114 | runOnUiThread (new Runnable() { 115 | public void run() { 116 | Log.i ("GStreamer", "Media size changed to " + width + "x" + height); 117 | gsv.media_width = width; 118 | gsv.media_height = height; 119 | runOnUiThread(new Runnable() { 120 | public void run() { 121 | gsv.requestLayout(); 122 | } 123 | }); 124 | } 125 | }); 126 | } 127 | }); 128 | 129 | SurfaceView sv = (SurfaceView) this.findViewById(R.id.surface_video); 130 | SurfaceHolder sh = sv.getHolder(); 131 | sh.addCallback(this); 132 | 133 | String mediaUri = null; 134 | Intent intent = getIntent(); 135 | android.net.Uri uri = intent.getData(); 136 | Log.i ("GStreamer", "Received URI: " + uri); 137 | if (uri.getScheme().equals("content")) { 138 | android.database.Cursor cursor = getContentResolver().query(uri, null, null, null, null); 139 | cursor.moveToFirst(); 140 | mediaUri = "file://" + cursor.getString(cursor.getColumnIndex(android.provider.MediaStore.Video.Media.DATA)); 141 | cursor.close(); 142 | } else { 143 | mediaUri = uri.toString(); 144 | } 145 | player.setUri(mediaUri); 146 | 147 | updateTimeWidget(); 148 | } 149 | 150 | protected void onDestroy() { 151 | player.close(); 152 | super.onDestroy(); 153 | } 154 | 155 | private void updateTimeWidget () { 156 | final TextView tv = (TextView) this.findViewById(R.id.textview_time); 157 | final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); 158 | final int pos = sb.getProgress(); 159 | final int max = sb.getMax(); 160 | 161 | SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); 162 | df.setTimeZone(TimeZone.getTimeZone("UTC")); 163 | final String message = df.format(new Date (pos)) + " / " + df.format(new Date (max)); 164 | tv.setText(message); 165 | } 166 | 167 | public void surfaceChanged(SurfaceHolder holder, int format, int width, 168 | int height) { 169 | Log.d("GStreamer", "Surface changed to format " + format + " width " 170 | + width + " height " + height); 171 | player.setSurface(holder.getSurface()); 172 | } 173 | 174 | public void surfaceCreated(SurfaceHolder holder) { 175 | Log.d("GStreamer", "Surface created: " + holder.getSurface()); 176 | } 177 | 178 | public void surfaceDestroyed(SurfaceHolder holder) { 179 | Log.d("GStreamer", "Surface destroyed"); 180 | player.setSurface(null); 181 | } 182 | 183 | public void onProgressChanged(SeekBar sb, int progress, boolean fromUser) { 184 | if (!fromUser) return; 185 | 186 | updateTimeWidget(); 187 | } 188 | 189 | public void onStartTrackingTouch(SeekBar sb) { 190 | } 191 | 192 | public void onStopTrackingTouch(SeekBar sb) { 193 | Log.d("GStreamer", "Seek to " + sb.getProgress()); 194 | player.seek(((long) sb.getProgress()) * 1000000); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /android/app/src/main/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_MODULE := gstplayer 6 | LOCAL_SRC_FILES := player.c 7 | 8 | LOCAL_SHARED_LIBRARIES := gstreamer_android 9 | LOCAL_LDLIBS := -llog -landroid 10 | include $(BUILD_SHARED_LIBRARY) 11 | 12 | ifeq ($(TARGET_ARCH_ABI),armeabi) 13 | GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARM) 14 | else ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) 15 | GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARMV7) 16 | else ifeq ($(TARGET_ARCH_ABI),arm64-v8a) 17 | GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARM64) 18 | else ifeq ($(TARGET_ARCH_ABI),x86) 19 | GSTREAMER_ROOT := $(GSTREAMER_ROOT_X86) 20 | else ifeq ($(TARGET_ARCH_ABI),x86_64) 21 | GSTREAMER_ROOT := $(GSTREAMER_ROOT_X86_64) 22 | else 23 | $(error Target arch ABI not supported) 24 | endif 25 | 26 | ifndef GSTREAMER_ROOT 27 | ifndef GSTREAMER_ROOT_ANDROID 28 | $(error GSTREAMER_ROOT_ANDROID is not defined!) 29 | endif 30 | GSTREAMER_ROOT := $(GSTREAMER_ROOT_ANDROID) 31 | endif 32 | 33 | GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/ 34 | 35 | include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk 36 | GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_PLUGINS_CODECS_RESTRICTED) $(GSTREAMER_CODECS_GPL) $(GSTREAMER_PLUGINS_ENCODING) $(GSTREAMER_PLUGINS_VIS) $(GSTREAMER_PLUGINS_EFFECTS) $(GSTREAMER_PLUGINS_NET_RESTRICTED) 37 | GSTREAMER_EXTRA_DEPS := gstreamer-player-1.0 gstreamer-video-1.0 glib-2.0 38 | 39 | include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk 40 | -------------------------------------------------------------------------------- /android/app/src/main/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_PLATFORM = 15 2 | -------------------------------------------------------------------------------- /android/app/src/main/jni/player.c: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2014 Sebastian Dröge 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | GST_DEBUG_CATEGORY_STATIC (debug_category); 31 | #define GST_CAT_DEFAULT debug_category 32 | 33 | #define GET_CUSTOM_DATA(env, thiz, fieldID) (Player *)(gintptr)(*env)->GetLongField (env, thiz, fieldID) 34 | #define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)(gintptr)data) 35 | 36 | typedef struct _Player 37 | { 38 | jobject java_player; 39 | GstPlayer *player; 40 | GstPlayerVideoRenderer *renderer; 41 | ANativeWindow *native_window; 42 | } Player; 43 | 44 | static pthread_key_t current_jni_env; 45 | static JavaVM *java_vm; 46 | static jfieldID native_player_field_id; 47 | static jmethodID on_position_updated_method_id; 48 | static jmethodID on_duration_changed_method_id; 49 | static jmethodID on_state_changed_method_id; 50 | static jmethodID on_buffering_method_id; 51 | static jmethodID on_end_of_stream_method_id; 52 | static jmethodID on_error_method_id; 53 | static jmethodID on_video_dimensions_changed_method_id; 54 | 55 | /* Register this thread with the VM */ 56 | static JNIEnv * 57 | attach_current_thread (void) 58 | { 59 | JNIEnv *env; 60 | JavaVMAttachArgs args; 61 | 62 | GST_DEBUG ("Attaching thread %p", g_thread_self ()); 63 | args.version = JNI_VERSION_1_4; 64 | args.name = NULL; 65 | args.group = NULL; 66 | 67 | if ((*java_vm)->AttachCurrentThread (java_vm, &env, &args) < 0) { 68 | GST_ERROR ("Failed to attach current thread"); 69 | return NULL; 70 | } 71 | 72 | return env; 73 | } 74 | 75 | /* Unregister this thread from the VM */ 76 | static void 77 | detach_current_thread (void *env) 78 | { 79 | GST_DEBUG ("Detaching thread %p", g_thread_self ()); 80 | (*java_vm)->DetachCurrentThread (java_vm); 81 | } 82 | 83 | /* Retrieve the JNI environment for this thread */ 84 | static JNIEnv * 85 | get_jni_env (void) 86 | { 87 | JNIEnv *env; 88 | 89 | if ((env = pthread_getspecific (current_jni_env)) == NULL) { 90 | env = attach_current_thread (); 91 | pthread_setspecific (current_jni_env, env); 92 | } 93 | 94 | return env; 95 | } 96 | 97 | /* 98 | * Java Bindings 99 | */ 100 | static void 101 | on_position_updated (GstPlayer * unused, GstClockTime position, Player * player) 102 | { 103 | JNIEnv *env = get_jni_env (); 104 | 105 | (*env)->CallVoidMethod (env, player->java_player, 106 | on_position_updated_method_id, position); 107 | if ((*env)->ExceptionCheck (env)) { 108 | (*env)->ExceptionDescribe (env); 109 | (*env)->ExceptionClear (env); 110 | } 111 | } 112 | 113 | static void 114 | on_duration_changed (GstPlayer * unused, GstClockTime duration, Player * player) 115 | { 116 | JNIEnv *env = get_jni_env (); 117 | 118 | (*env)->CallVoidMethod (env, player->java_player, 119 | on_duration_changed_method_id, duration); 120 | if ((*env)->ExceptionCheck (env)) { 121 | (*env)->ExceptionDescribe (env); 122 | (*env)->ExceptionClear (env); 123 | } 124 | } 125 | 126 | static void 127 | on_state_changed (GstPlayer * unused, GstPlayerState state, Player * player) 128 | { 129 | JNIEnv *env = get_jni_env (); 130 | 131 | (*env)->CallVoidMethod (env, player->java_player, 132 | on_state_changed_method_id, state); 133 | if ((*env)->ExceptionCheck (env)) { 134 | (*env)->ExceptionDescribe (env); 135 | (*env)->ExceptionClear (env); 136 | } 137 | } 138 | 139 | static void 140 | on_buffering (GstPlayer * unused, gint percent, Player * player) 141 | { 142 | JNIEnv *env = get_jni_env (); 143 | 144 | (*env)->CallVoidMethod (env, player->java_player, 145 | on_buffering_method_id, percent); 146 | if ((*env)->ExceptionCheck (env)) { 147 | (*env)->ExceptionDescribe (env); 148 | (*env)->ExceptionClear (env); 149 | } 150 | } 151 | 152 | static void 153 | on_end_of_stream (GstPlayer * unused, Player * player) 154 | { 155 | JNIEnv *env = get_jni_env (); 156 | 157 | (*env)->CallVoidMethod (env, player->java_player, on_end_of_stream_method_id); 158 | if ((*env)->ExceptionCheck (env)) { 159 | (*env)->ExceptionDescribe (env); 160 | (*env)->ExceptionClear (env); 161 | } 162 | } 163 | 164 | static void 165 | on_error (GstPlayer * unused, GError * err, Player * player) 166 | { 167 | JNIEnv *env = get_jni_env (); 168 | jstring error_msg; 169 | 170 | error_msg = (*env)->NewStringUTF (env, err->message); 171 | 172 | (*env)->CallVoidMethod (env, player->java_player, on_error_method_id, 173 | err->code, error_msg); 174 | if ((*env)->ExceptionCheck (env)) { 175 | (*env)->ExceptionDescribe (env); 176 | (*env)->ExceptionClear (env); 177 | } 178 | 179 | (*env)->DeleteLocalRef (env, error_msg); 180 | } 181 | 182 | static void 183 | on_video_dimensions_changed (GstPlayer * unused, gint width, gint height, 184 | Player * player) 185 | { 186 | JNIEnv *env = get_jni_env (); 187 | 188 | (*env)->CallVoidMethod (env, player->java_player, 189 | on_video_dimensions_changed_method_id, width, height); 190 | if ((*env)->ExceptionCheck (env)) { 191 | (*env)->ExceptionDescribe (env); 192 | (*env)->ExceptionClear (env); 193 | } 194 | } 195 | 196 | static void 197 | native_new (JNIEnv * env, jobject thiz) 198 | { 199 | Player *player = g_new0 (Player, 1); 200 | 201 | player->renderer = gst_player_video_overlay_video_renderer_new (NULL); 202 | player->player = gst_player_new (player->renderer, NULL); 203 | SET_CUSTOM_DATA (env, thiz, native_player_field_id, player); 204 | player->java_player = (*env)->NewGlobalRef (env, thiz); 205 | 206 | g_signal_connect (player->player, "position-updated", 207 | G_CALLBACK (on_position_updated), player); 208 | g_signal_connect (player->player, "duration-changed", 209 | G_CALLBACK (on_duration_changed), player); 210 | g_signal_connect (player->player, "state-changed", 211 | G_CALLBACK (on_state_changed), player); 212 | g_signal_connect (player->player, "buffering", 213 | G_CALLBACK (on_buffering), player); 214 | g_signal_connect (player->player, "end-of-stream", 215 | G_CALLBACK (on_end_of_stream), player); 216 | g_signal_connect (player->player, "error", G_CALLBACK (on_error), player); 217 | g_signal_connect (player->player, "video-dimensions-changed", 218 | G_CALLBACK (on_video_dimensions_changed), player); 219 | } 220 | 221 | static void 222 | native_free (JNIEnv * env, jobject thiz) 223 | { 224 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 225 | 226 | if (!player) 227 | return; 228 | 229 | g_object_unref (player->player); 230 | (*env)->DeleteGlobalRef (env, player->java_player); 231 | g_free (player); 232 | SET_CUSTOM_DATA (env, thiz, native_player_field_id, NULL); 233 | } 234 | 235 | static void 236 | native_play (JNIEnv * env, jobject thiz) 237 | { 238 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 239 | 240 | if (!player) 241 | return; 242 | 243 | gst_player_play (player->player); 244 | } 245 | 246 | static void 247 | native_pause (JNIEnv * env, jobject thiz) 248 | { 249 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 250 | 251 | if (!player) 252 | return; 253 | 254 | gst_player_pause (player->player); 255 | } 256 | 257 | static void 258 | native_stop (JNIEnv * env, jobject thiz) 259 | { 260 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 261 | 262 | if (!player) 263 | return; 264 | 265 | gst_player_stop (player->player); 266 | } 267 | 268 | static void 269 | native_seek (JNIEnv * env, jobject thiz, jlong position) 270 | { 271 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 272 | 273 | if (!player) 274 | return; 275 | 276 | gst_player_seek (player->player, position); 277 | } 278 | 279 | static void 280 | native_set_uri (JNIEnv * env, jobject thiz, jobject uri) 281 | { 282 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 283 | const gchar *uri_str; 284 | 285 | if (!player) 286 | return; 287 | 288 | uri_str = (*env)->GetStringUTFChars (env, uri, NULL); 289 | g_object_set (player->player, "uri", uri_str, NULL); 290 | (*env)->ReleaseStringUTFChars (env, uri, uri_str); 291 | } 292 | 293 | static jobject 294 | native_get_uri (JNIEnv * env, jobject thiz) 295 | { 296 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 297 | jobject uri; 298 | gchar *uri_str; 299 | 300 | if (!player) 301 | return NULL; 302 | 303 | g_object_get (player->player, "uri", &uri_str, NULL); 304 | 305 | uri = (*env)->NewStringUTF (env, uri_str); 306 | g_free (uri_str); 307 | 308 | return uri; 309 | } 310 | 311 | static jlong 312 | native_get_position (JNIEnv * env, jobject thiz) 313 | { 314 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 315 | jdouble position; 316 | 317 | if (!player) 318 | return -1; 319 | 320 | g_object_get (player->player, "position", &position, NULL); 321 | 322 | return position; 323 | } 324 | 325 | static jlong 326 | native_get_duration (JNIEnv * env, jobject thiz) 327 | { 328 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 329 | jlong duration; 330 | 331 | if (!player) 332 | return -1; 333 | 334 | g_object_get (player->player, "duration", &duration, NULL); 335 | 336 | return duration; 337 | } 338 | 339 | static jdouble 340 | native_get_volume (JNIEnv * env, jobject thiz) 341 | { 342 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 343 | jdouble volume; 344 | 345 | if (!player) 346 | return 1.0; 347 | 348 | g_object_get (player->player, "volume", &volume, NULL); 349 | 350 | return volume; 351 | } 352 | 353 | static void 354 | native_set_volume (JNIEnv * env, jobject thiz, jdouble volume) 355 | { 356 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 357 | 358 | if (!player) 359 | return; 360 | 361 | g_object_set (player->player, "volume", volume, NULL); 362 | } 363 | 364 | static jboolean 365 | native_get_mute (JNIEnv * env, jobject thiz) 366 | { 367 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 368 | jboolean mute; 369 | 370 | if (!player) 371 | return FALSE; 372 | 373 | g_object_get (player->player, "mute", &mute, NULL); 374 | 375 | return mute; 376 | } 377 | 378 | static void 379 | native_set_mute (JNIEnv * env, jobject thiz, jboolean mute) 380 | { 381 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 382 | 383 | if (!player) 384 | return; 385 | 386 | g_object_set (player->player, "mute", mute, NULL); 387 | } 388 | 389 | static void 390 | native_set_surface (JNIEnv * env, jobject thiz, jobject surface) 391 | { 392 | Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); 393 | ANativeWindow *new_native_window; 394 | 395 | if (!player) 396 | return; 397 | 398 | new_native_window = surface ? ANativeWindow_fromSurface (env, surface) : NULL; 399 | GST_DEBUG ("Received surface %p (native window %p)", surface, 400 | new_native_window); 401 | 402 | if (player->native_window) { 403 | ANativeWindow_release (player->native_window); 404 | } 405 | 406 | player->native_window = new_native_window; 407 | gst_player_video_overlay_video_renderer_set_window_handle 408 | (GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (player->renderer), 409 | (gpointer) new_native_window); 410 | } 411 | 412 | static void 413 | native_class_init (JNIEnv * env, jclass klass) 414 | { 415 | native_player_field_id = 416 | (*env)->GetFieldID (env, klass, "native_player", "J"); 417 | on_position_updated_method_id = 418 | (*env)->GetMethodID (env, klass, "onPositionUpdated", "(J)V"); 419 | on_duration_changed_method_id = 420 | (*env)->GetMethodID (env, klass, "onDurationChanged", "(J)V"); 421 | on_state_changed_method_id = 422 | (*env)->GetMethodID (env, klass, "onStateChanged", "(I)V"); 423 | on_buffering_method_id = 424 | (*env)->GetMethodID (env, klass, "onBuffering", "(I)V"); 425 | on_end_of_stream_method_id = 426 | (*env)->GetMethodID (env, klass, "onEndOfStream", "()V"); 427 | on_error_method_id = 428 | (*env)->GetMethodID (env, klass, "onError", "(ILjava/lang/String;)V"); 429 | on_video_dimensions_changed_method_id = 430 | (*env)->GetMethodID (env, klass, "onVideoDimensionsChanged", "(II)V"); 431 | 432 | if (!native_player_field_id || 433 | !on_position_updated_method_id || !on_duration_changed_method_id || 434 | !on_state_changed_method_id || !on_buffering_method_id || 435 | !on_end_of_stream_method_id || 436 | !on_error_method_id || !on_video_dimensions_changed_method_id) { 437 | static const gchar *message = 438 | "The calling class does not implement all necessary interface methods"; 439 | jclass exception_class = (*env)->FindClass (env, "java/lang/Exception"); 440 | __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", "%s", message); 441 | (*env)->ThrowNew (env, exception_class, message); 442 | } 443 | 444 | gst_debug_set_threshold_for_name ("gst-player", GST_LEVEL_TRACE); 445 | } 446 | 447 | /* List of implemented native methods */ 448 | static JNINativeMethod native_methods[] = { 449 | {"nativeClassInit", "()V", (void *) native_class_init}, 450 | {"nativeNew", "()V", (void *) native_new}, 451 | {"nativePlay", "()V", (void *) native_play}, 452 | {"nativePause", "()V", (void *) native_pause}, 453 | {"nativeStop", "()V", (void *) native_stop}, 454 | {"nativeSeek", "(J)V", (void *) native_seek}, 455 | {"nativeFree", "()V", (void *) native_free}, 456 | {"nativeGetUri", "()Ljava/lang/String;", (void *) native_get_uri}, 457 | {"nativeSetUri", "(Ljava/lang/String;)V", (void *) native_set_uri}, 458 | {"nativeGetPosition", "()J", (void *) native_get_position}, 459 | {"nativeGetDuration", "()J", (void *) native_get_duration}, 460 | {"nativeGetVolume", "()D", (void *) native_get_volume}, 461 | {"nativeSetVolume", "(D)V", (void *) native_set_volume}, 462 | {"nativeGetMute", "()Z", (void *) native_get_mute}, 463 | {"nativeSetMute", "(Z)V", (void *) native_set_mute}, 464 | {"nativeSetSurface", "(Landroid/view/Surface;)V", 465 | (void *) native_set_surface} 466 | }; 467 | 468 | /* Library initializer */ 469 | jint 470 | JNI_OnLoad (JavaVM * vm, void *reserved) 471 | { 472 | JNIEnv *env = NULL; 473 | 474 | java_vm = vm; 475 | 476 | if ((*vm)->GetEnv (vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) { 477 | __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", 478 | "Could not retrieve JNIEnv"); 479 | return 0; 480 | } 481 | jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/Player"); 482 | if (!klass) { 483 | __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", 484 | "Could not retrieve class org.freedesktop.gstreamer.Player"); 485 | return 0; 486 | } 487 | if ((*env)->RegisterNatives (env, klass, native_methods, 488 | G_N_ELEMENTS (native_methods))) { 489 | __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", 490 | "Could not register native methods for org.freedesktop.gstreamer.Player"); 491 | return 0; 492 | } 493 | 494 | pthread_key_create (¤t_jni_env, detach_current_thread); 495 | 496 | return JNI_VERSION_1_4; 497 | } 498 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 22 | 23 | 30 | 31 | 32 | 38 | 39 | 46 | 47 | 54 | 55 | 56 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | GStreamer Play 4 | Play 5 | Pause 6 | 7 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.1.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdroege/gst-player/ee3c226c82767a089743e4e06058743e67f73cdb/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Aug 23 11:07:06 IST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | srcdir=`dirname $0` 4 | test -z "$srcdir" && srcdir=. 5 | 6 | ORIGDIR=`pwd` 7 | cd $srcdir 8 | 9 | # Automake requires that ChangeLog exist. 10 | touch ChangeLog 11 | mkdir -p m4 12 | 13 | autoreconf -v --install || exit 1 14 | cd $ORIGDIR || exit $? 15 | 16 | $srcdir/configure --enable-maintainer-mode --enable-more-warnings --enable-warnings-as-errors "$@" 17 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([gst-player], [0.0.1]) 2 | AC_CONFIG_SRCDIR([Makefile.am]) 3 | AC_CONFIG_MACRO_DIR([m4]) 4 | AC_CONFIG_HEADERS(config.h) 5 | 6 | AM_INIT_AUTOMAKE([-Wno-portability 1.11 no-dist-gzip dist-xz tar-ustar subdir-objects]) 7 | AM_MAINTAINER_MODE 8 | 9 | LT_PREREQ([2.2.6]) 10 | LT_INIT([dlopen win32-dll pic-only]) 11 | 12 | m4_ifdef([AM_SILENT_RULES], 13 | [AM_SILENT_RULES([yes])], 14 | [ 15 | AM_DEFAULT_VERBOSITY=1 16 | AC_SUBST(AM_DEFAULT_VERBOSITY) 17 | ] 18 | ) 19 | 20 | AC_PROG_CC 21 | AC_PROG_CC_STDC 22 | AC_PROG_CPP 23 | AC_PROG_INSTALL 24 | AM_PROG_CC_C_O 25 | 26 | AC_HEADER_STDC 27 | AC_C_CONST 28 | AC_C_INLINE 29 | AC_ISC_POSIX 30 | AC_SYS_LARGEFILE 31 | 32 | AC_C_BIGENDIAN 33 | 34 | AC_CHECK_LIBM 35 | AC_SUBST(LIBM) 36 | 37 | PKG_PROG_PKG_CONFIG 38 | 39 | PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.38.0 gobject-2.0 >= 2.38.0]) 40 | PKG_CHECK_MODULES(GSTREAMER, [gstreamer-1.0 gstreamer-tag-1.0 gstreamer-player-1.0 >= 1.7.1.1]) 41 | 42 | GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`" 43 | AC_SUBST(GLIB_PREFIX) 44 | GST_PREFIX="`$PKG_CONFIG --variable=prefix gstreamer-1.0`" 45 | AC_SUBST(GST_PREFIX) 46 | 47 | PKG_CHECK_MODULES(GTK, [gtk+-3.0 >= 3.14], [have_gtk="yes"], [have_gtk="no"]) 48 | AM_CONDITIONAL(HAVE_GTK, test "x$have_gtk" != "xno") 49 | 50 | PKG_CHECK_MODULES(GMODULE, [gmodule-2.0], [have_gmodules="yes"], [have_modules="no"]) 51 | AM_CONDITIONAL(HAVE_GMODULE, test "x$have_gmodules" != "xno") 52 | 53 | PKG_CHECK_MODULES(GTK_X11, [gtk+-x11-3.0 x11], [have_gtk_x11="yes"], [have_gtk_x11="no"]) 54 | AM_CONDITIONAL(HAVE_GTK_X11, test "x$have_gtk_x11" != "xno") 55 | 56 | WARNING_CFLAGS="-Wall" 57 | 58 | AC_ARG_ENABLE(more-warnings, 59 | AC_HELP_STRING([--enable-more-warnings], [Enable more compiler warnings]), 60 | set_more_warnings="$enableval", set_more_warnings=no) 61 | 62 | AC_MSG_CHECKING(for more warnings) 63 | if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then 64 | AC_MSG_RESULT(yes) 65 | 66 | for option in -Wchar-subscripts -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wpointer-arith -Wredundant-decls -Wundef -Wwrite-strings -Wformat-nonliteral -Wformat-security -Wold-style-definition -Winit-self -Wmissing-include-dirs -Waddress -Waggregate-return -Wno-multichar -Wunused-variable; do 67 | SAVE_CFLAGS="$CFLAGS" 68 | CFLAGS="$CFLAGS $WARNING_CFLAGS $option" 69 | AC_MSG_CHECKING([whether gcc understands $option]) 70 | AC_TRY_COMPILE([], [], 71 | has_option=yes, 72 | has_option=no,) 73 | if test x"$has_option" = "xyes"; then 74 | WARNING_CFLAGS="$WARNING_CFLAGS $option" 75 | fi 76 | CFLAGS="$SAVE_CFLAGS" 77 | AC_MSG_RESULT($has_option) 78 | unset has_option 79 | unset SAVE_CFLAGS 80 | done 81 | unset option 82 | else 83 | AC_MSG_RESULT(no) 84 | fi 85 | 86 | AC_ARG_ENABLE(warnings-as-errors, 87 | AC_HELP_STRING([--enable-warnings-as-errors], [Handle compiler warnings as errors]), 88 | set_werror="$enableval", set_werror=no) 89 | 90 | AC_MSG_CHECKING(for handling compiler warnings as errors) 91 | if test "$GCC" = "yes" -a "$set_werror" != "no"; then 92 | AC_MSG_RESULT(yes) 93 | WARNING_CFLAGS="$WARNING_CFLAGS -Werror" 94 | else 95 | AC_MSG_RESULT(no) 96 | fi 97 | 98 | AC_SUBST(WARNING_CFLAGS) 99 | 100 | AC_CONFIG_FILES([ 101 | Makefile 102 | gst-play/Makefile 103 | gtk/Makefile 104 | android/Makefile 105 | ios/Makefile 106 | ]) 107 | 108 | AC_OUTPUT 109 | -------------------------------------------------------------------------------- /gst-play/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = gst-play 2 | 3 | gst_play_SOURCES = gst-play.c gst-play-kb.c gst-play-kb.h 4 | 5 | LDADD = $(GSTREAMER_LIBS) $(GLIB_LIBS) $(LIBM) 6 | 7 | AM_CFLAGS = $(GSTREAMER_CFLAGS) $(GLIB_CFLAGS) $(WARNING_CFLAGS) 8 | 9 | noinst_HEADERS = gst-play-kb.h 10 | -------------------------------------------------------------------------------- /gst-play/gst-play-kb.c: -------------------------------------------------------------------------------- 1 | /* GStreamer command line playback testing utility - keyboard handling helpers 2 | * 3 | * Copyright (C) 2013 Tim-Philipp Müller 4 | * Copyright (C) 2013 Centricular Ltd 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 19 | * Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | #ifdef HAVE_CONFIG_H 23 | #include "config.h" 24 | #endif 25 | 26 | #include "gst-play-kb.h" 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #ifdef G_OS_UNIX 33 | #include 34 | #include 35 | #endif 36 | 37 | #include 38 | 39 | /* This is all not thread-safe, but doesn't have to be really */ 40 | 41 | #ifdef G_OS_UNIX 42 | 43 | static struct termios term_settings; 44 | static gboolean term_settings_saved = FALSE; 45 | static GstPlayKbFunc kb_callback; 46 | static gpointer kb_callback_data; 47 | static gulong io_watch_id; 48 | 49 | static gboolean 50 | gst_play_kb_io_cb (GIOChannel * ioc, GIOCondition cond, gpointer user_data) 51 | { 52 | GIOStatus status; 53 | 54 | if (cond & G_IO_IN) { 55 | gchar buf[16] = { 0, }; 56 | gsize read; 57 | 58 | status = g_io_channel_read_chars (ioc, buf, sizeof (buf) - 1, &read, NULL); 59 | if (status == G_IO_STATUS_ERROR) 60 | return FALSE; 61 | if (status == G_IO_STATUS_NORMAL) { 62 | if (kb_callback) 63 | kb_callback (buf, kb_callback_data); 64 | } 65 | } 66 | 67 | return TRUE; /* call us again */ 68 | } 69 | 70 | gboolean 71 | gst_play_kb_set_key_handler (GstPlayKbFunc kb_func, gpointer user_data) 72 | { 73 | GIOChannel *ioc; 74 | int flags; 75 | 76 | if (!isatty (STDIN_FILENO)) { 77 | GST_INFO ("stdin is not connected to a terminal"); 78 | return FALSE; 79 | } 80 | 81 | if (io_watch_id > 0) { 82 | g_source_remove (io_watch_id); 83 | io_watch_id = 0; 84 | } 85 | 86 | if (kb_func == NULL && term_settings_saved) { 87 | /* restore terminal settings */ 88 | if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &term_settings) == 0) 89 | term_settings_saved = FALSE; 90 | else 91 | g_warning ("could not restore terminal attributes"); 92 | 93 | setvbuf (stdin, NULL, _IOLBF, 0); 94 | } 95 | 96 | if (kb_func != NULL) { 97 | struct termios new_settings; 98 | 99 | if (!term_settings_saved) { 100 | if (tcgetattr (STDIN_FILENO, &term_settings) != 0) { 101 | g_warning ("could not save terminal attributes"); 102 | return FALSE; 103 | } 104 | term_settings_saved = TRUE; 105 | 106 | /* Echo off, canonical mode off, extended input processing off */ 107 | new_settings = term_settings; 108 | new_settings.c_lflag &= ~(ECHO | ICANON | IEXTEN); 109 | 110 | if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &new_settings) != 0) { 111 | g_warning ("Could not set terminal state"); 112 | return FALSE; 113 | } 114 | setvbuf (stdin, NULL, _IONBF, 0); 115 | } 116 | } 117 | 118 | ioc = g_io_channel_unix_new (STDIN_FILENO); 119 | 120 | /* make non-blocking */ 121 | flags = g_io_channel_get_flags (ioc); 122 | g_io_channel_set_flags (ioc, flags | G_IO_FLAG_NONBLOCK, NULL); 123 | 124 | io_watch_id = g_io_add_watch_full (ioc, G_PRIORITY_DEFAULT, G_IO_IN, 125 | (GIOFunc) gst_play_kb_io_cb, user_data, NULL); 126 | g_io_channel_unref (ioc); 127 | 128 | kb_callback = kb_func; 129 | kb_callback_data = user_data; 130 | 131 | return TRUE; 132 | } 133 | 134 | #else /* !G_OS_UNIX */ 135 | 136 | gboolean 137 | gst_play_kb_set_key_handler (GstPlayKbFunc key_func, gpointer user_data) 138 | { 139 | GST_FIXME ("Keyboard handling for this OS needs to be implemented"); 140 | return FALSE; 141 | } 142 | 143 | #endif /* !G_OS_UNIX */ 144 | -------------------------------------------------------------------------------- /gst-play/gst-play-kb.h: -------------------------------------------------------------------------------- 1 | /* GStreamer command line playback testing utility - keyboard handling helpers 2 | * 3 | * Copyright (C) 2013 Tim-Philipp Müller 4 | * Copyright (C) 2013 Centricular Ltd 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 19 | * Boston, MA 02110-1301, USA. 20 | */ 21 | #ifndef __GST_PLAY_KB_INCLUDED__ 22 | #define __GST_PLAY_KB_INCLUDED__ 23 | 24 | #include 25 | 26 | #define GST_PLAY_KB_ARROW_UP "\033[A" 27 | #define GST_PLAY_KB_ARROW_DOWN "\033[B" 28 | #define GST_PLAY_KB_ARROW_RIGHT "\033[C" 29 | #define GST_PLAY_KB_ARROW_LEFT "\033[D" 30 | 31 | typedef void (*GstPlayKbFunc) (const gchar * kb_input, gpointer user_data); 32 | 33 | gboolean gst_play_kb_set_key_handler (GstPlayKbFunc kb_func, gpointer user_data); 34 | 35 | #endif /* __GST_PLAY_KB_INCLUDED__ */ 36 | -------------------------------------------------------------------------------- /gtk/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = gtk-play 2 | 3 | gtk-play-resources.c: resources/gresources.xml \ 4 | resources/media_info_dialog.ui \ 5 | resources/toolbar.css \ 6 | resources/toolbar.ui 7 | $(AM_V_GEN) \ 8 | glib-compile-resources \ 9 | --sourcedir=$(srcdir)/resources \ 10 | --target=$@ \ 11 | --generate-source \ 12 | --c-name as \ 13 | $(srcdir)/resources/gresources.xml 14 | 15 | gtk-play-resources.h: resources/gresources.xml \ 16 | resources/media_info_dialog.ui \ 17 | resources/toolbar.css \ 18 | resources/toolbar.ui 19 | $(AM_V_GEN) \ 20 | glib-compile-resources \ 21 | --sourcedir=$(srcdir)/resources \ 22 | --target=$@ \ 23 | --generate-header \ 24 | --c-name as \ 25 | $(srcdir)/resources/gresources.xml 26 | 27 | BUILT_SOURCES: gtk-play-resources.c gtk-play-resources.h 28 | 29 | gtk_play_SOURCES = gtk-play.c gtk-play-resources.c gtk-video-renderer.c 30 | 31 | LDADD = $(GSTREAMER_LIBS) $(GTK_LIBS) $(GTK_X11_LIBS) $(GLIB_LIBS) $(LIBM) $(GMODULE_LIBS) 32 | 33 | AM_CFLAGS = $(GSTREAMER_CFLAGS) $(GTK_CFLAGS) $(GTK_X11_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) $(WARNING_CFLAGS) 34 | 35 | noinst_HEADERS = gtk-play-resources.h gtk-video-renderer.h 36 | -------------------------------------------------------------------------------- /gtk/gtk-video-renderer.c: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2015 Sebastian Dröge 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #include "gtk-video-renderer.h" 22 | 23 | struct _GstPlayerGtkVideoRenderer 24 | { 25 | GObject parent; 26 | 27 | GstElement *sink; 28 | GtkWidget *widget; 29 | }; 30 | 31 | struct _GstPlayerGtkVideoRendererClass 32 | { 33 | GObjectClass parent_class; 34 | }; 35 | 36 | static void 37 | gst_player_gtk_video_renderer_interface_init 38 | (GstPlayerVideoRendererInterface * iface); 39 | 40 | enum 41 | { 42 | GTK_VIDEO_RENDERER_PROP_0, 43 | GTK_VIDEO_RENDERER_PROP_WIDGET, 44 | GTK_VIDEO_RENDERER_PROP_LAST 45 | }; 46 | 47 | G_DEFINE_TYPE_WITH_CODE (GstPlayerGtkVideoRenderer, 48 | gst_player_gtk_video_renderer, G_TYPE_OBJECT, 49 | G_IMPLEMENT_INTERFACE (GST_TYPE_PLAYER_VIDEO_RENDERER, 50 | gst_player_gtk_video_renderer_interface_init)); 51 | 52 | static GParamSpec 53 | * gtk_video_renderer_param_specs[GTK_VIDEO_RENDERER_PROP_LAST] = { NULL, }; 54 | 55 | static void 56 | gst_player_gtk_video_renderer_get_property (GObject * object, 57 | guint prop_id, GValue * value, GParamSpec * pspec) 58 | { 59 | GstPlayerGtkVideoRenderer *self = GST_PLAYER_GTK_VIDEO_RENDERER (object); 60 | 61 | switch (prop_id) { 62 | case GTK_VIDEO_RENDERER_PROP_WIDGET: 63 | g_value_set_object (value, self->widget); 64 | break; 65 | default: 66 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 67 | break; 68 | } 69 | } 70 | 71 | static void 72 | gst_player_gtk_video_renderer_finalize (GObject * object) 73 | { 74 | GstPlayerGtkVideoRenderer *self = GST_PLAYER_GTK_VIDEO_RENDERER (object); 75 | 76 | if (self->sink) 77 | gst_object_unref (self->sink); 78 | if (self->widget) 79 | g_object_unref (self->widget); 80 | 81 | G_OBJECT_CLASS 82 | (gst_player_gtk_video_renderer_parent_class)->finalize (object); 83 | } 84 | 85 | static void 86 | gst_player_gtk_video_renderer_class_init 87 | (GstPlayerGtkVideoRendererClass * klass) 88 | { 89 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 90 | 91 | gobject_class->get_property = gst_player_gtk_video_renderer_get_property; 92 | gobject_class->finalize = gst_player_gtk_video_renderer_finalize; 93 | 94 | gtk_video_renderer_param_specs 95 | [GTK_VIDEO_RENDERER_PROP_WIDGET] = 96 | g_param_spec_object ("widget", "Widget", 97 | "Widget to render the video into", GTK_TYPE_WIDGET, 98 | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); 99 | 100 | g_object_class_install_properties (gobject_class, 101 | GTK_VIDEO_RENDERER_PROP_LAST, gtk_video_renderer_param_specs); 102 | } 103 | 104 | static void 105 | gst_player_gtk_video_renderer_init (GstPlayerGtkVideoRenderer * self) 106 | { 107 | GstElement *gtk_sink = gst_element_factory_make ("gtkglsink", NULL); 108 | 109 | if (gtk_sink) { 110 | GstElement *sink = gst_element_factory_make ("glsinkbin", NULL); 111 | g_object_set (sink, "sink", gtk_sink, NULL); 112 | 113 | self->sink = sink; 114 | } else { 115 | gtk_sink = gst_element_factory_make ("gtksink", NULL); 116 | 117 | self->sink = gst_object_ref (gtk_sink); 118 | } 119 | 120 | g_assert (self->sink != NULL); 121 | 122 | g_object_get (gtk_sink, "widget", &self->widget, NULL); 123 | gst_object_unref (gtk_sink); 124 | } 125 | 126 | static GstElement *gst_player_gtk_video_renderer_create_video_sink 127 | (GstPlayerVideoRenderer * iface, GstPlayer * player) 128 | { 129 | GstPlayerGtkVideoRenderer *self = GST_PLAYER_GTK_VIDEO_RENDERER (iface); 130 | 131 | return gst_object_ref (self->sink); 132 | } 133 | 134 | static void 135 | gst_player_gtk_video_renderer_interface_init 136 | (GstPlayerVideoRendererInterface * iface) 137 | { 138 | iface->create_video_sink = gst_player_gtk_video_renderer_create_video_sink; 139 | } 140 | 141 | /** 142 | * gst_player_gtk_video_renderer_new: 143 | * 144 | * Returns: (transfer full): 145 | */ 146 | GstPlayerVideoRenderer * 147 | gst_player_gtk_video_renderer_new (void) 148 | { 149 | GstElementFactory *factory; 150 | 151 | factory = gst_element_factory_find ("gtkglsink"); 152 | if (!factory) 153 | factory = gst_element_factory_find ("gtksink"); 154 | if (!factory) 155 | return NULL; 156 | 157 | gst_object_unref (factory); 158 | 159 | return g_object_new (GST_TYPE_PLAYER_GTK_VIDEO_RENDERER, NULL); 160 | } 161 | 162 | /** 163 | * gst_player_gtk_video_renderer_get_widget: 164 | * @self: #GstPlayerVideoRenderer instance 165 | * 166 | * Returns: (transfer full): The GtkWidget 167 | */ 168 | GtkWidget *gst_player_gtk_video_renderer_get_widget 169 | (GstPlayerGtkVideoRenderer * self) 170 | { 171 | GtkWidget *widget; 172 | 173 | g_return_val_if_fail (GST_IS_PLAYER_GTK_VIDEO_RENDERER (self), NULL); 174 | 175 | g_object_get (self, "widget", &widget, NULL); 176 | 177 | return widget; 178 | } 179 | -------------------------------------------------------------------------------- /gtk/gtk-video-renderer.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2015 Sebastian Dröge 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef __GTK_VIDEO_RENDERER_H__ 22 | #define __GTK_VIDEO_RENDERER_H__ 23 | 24 | #include 25 | #include 26 | 27 | G_BEGIN_DECLS 28 | 29 | typedef struct _GstPlayerGtkVideoRenderer 30 | GstPlayerGtkVideoRenderer; 31 | typedef struct _GstPlayerGtkVideoRendererClass 32 | GstPlayerGtkVideoRendererClass; 33 | 34 | #define GST_TYPE_PLAYER_GTK_VIDEO_RENDERER (gst_player_gtk_video_renderer_get_type ()) 35 | #define GST_IS_PLAYER_GTK_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PLAYER_GTK_VIDEO_RENDERER)) 36 | #define GST_IS_PLAYER_GTK_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAYER_GTK_VIDEO_RENDERER)) 37 | #define GST_PLAYER_GTK_VIDEO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PLAYER_GTK_VIDEO_RENDERER, GstPlayerGtkVideoRendererClass)) 38 | #define GST_PLAYER_GTK_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PLAYER_GTK_VIDEO_RENDERER, GstPlayerGtkVideoRenderer)) 39 | #define GST_PLAYER_GTK_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PLAYER_GTK_VIDEO_RENDERER, GstPlayerGtkVideoRendererClass)) 40 | #define GST_PLAYER_GTK_VIDEO_RENDERER_CAST(obj) ((GstPlayerGtkVideoRenderer*)(obj)) 41 | 42 | GType gst_player_gtk_video_renderer_get_type (void); 43 | 44 | GstPlayerVideoRenderer * gst_player_gtk_video_renderer_new (void); 45 | GtkWidget * gst_player_gtk_video_renderer_get_widget (GstPlayerGtkVideoRenderer * self); 46 | 47 | G_END_DECLS 48 | 49 | #endif /* __GTK_VIDEO_RENDERER_H__ */ 50 | -------------------------------------------------------------------------------- /gtk/resources/gresources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | toolbar.ui 5 | media_info_dialog.ui 6 | 7 | 8 | toolbar.css 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /gtk/resources/media_info_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | media_info_dialog 13 | False 14 | center-on-parent 15 | dialog 16 | 17 | 18 | False 19 | vertical 20 | 2 21 | 22 | 23 | False 24 | end 25 | 26 | 27 | Close 28 | media_info_dialog_button 29 | True 30 | True 31 | True 32 | 33 | 34 | 35 | True 36 | True 37 | 0 38 | 39 | 40 | 41 | 42 | False 43 | False 44 | 0 45 | 46 | 47 | 48 | 49 | True 50 | False 51 | vertical 52 | 53 | 54 | True 55 | False 56 | 5 57 | Information about all the streams contains in your media. 58 | 59 | 60 | False 61 | True 62 | 0 63 | 64 | 65 | 66 | 67 | True 68 | True 69 | 5 70 | in 71 | 72 | 73 | True 74 | True 75 | tree 76 | False 77 | 78 | 79 | 80 | 81 | 82 | autosize 83 | col 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | True 94 | True 95 | 1 96 | 97 | 98 | 99 | 100 | True 101 | True 102 | 1 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /gtk/resources/toolbar.css: -------------------------------------------------------------------------------- 1 | * { 2 | background-color: rgba(43,56,54,0.0); 3 | padding: 0px; 4 | } 5 | 6 | GtkLabel { 7 | font-size: 10px; 8 | color: #ffffff; 9 | } 10 | 11 | #toolbar { 12 | border-radius: 25px; 13 | border: 3px solid #212B2A; 14 | background: rgba(43,56,54,0.6); 15 | } 16 | 17 | GtkButton:hover { 18 | border-radius: 45px; 19 | background: rgba(43,56,54,1.0); 20 | border: 1px solid #212B2A; 21 | } 22 | 23 | #title_label { 24 | font-size: 12px; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /gtk/resources/toolbar.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | True 8 | False 9 | 30 10 | media-seek-forward 11 | 0 12 | 13 | 14 | True 15 | False 16 | 25 17 | view-fullscreen 18 | 0 19 | 20 | 21 | True 22 | False 23 | 30 24 | media-skip-forward 25 | 0 26 | 27 | 28 | True 29 | False 30 | 35 31 | media-playback-pause 32 | 0 33 | 34 | 35 | True 36 | False 37 | 0 38 | 0 39 | 35 40 | media-playback-start 41 | 0 42 | 43 | 44 | True 45 | False 46 | 30 47 | media-skip-backward 48 | 49 | 50 | restore_image 51 | True 52 | False 53 | 25 54 | view-restore 55 | 0 56 | 57 | 58 | True 59 | False 60 | 30 61 | media-seek-backward 62 | 63 | 64 | toolbar 65 | True 66 | False 67 | 5 68 | vertical 69 | 70 | 71 | True 72 | False 73 | 20 74 | 20 75 | 9 76 | 77 | 78 | elapshed_time 79 | True 80 | False 81 | center 82 | 00:00 83 | 84 | 85 | False 86 | True 87 | 0 88 | 89 | 90 | 91 | 92 | seekbar 93 | True 94 | True 95 | center 96 | 1 97 | False 98 | 99 | 100 | 101 | True 102 | True 103 | 1 104 | 105 | 106 | 107 | 108 | remain_time 109 | True 110 | False 111 | center 112 | 00:00 113 | 114 | 115 | False 116 | True 117 | 2 118 | 119 | 120 | 121 | 122 | volume_button 123 | True 124 | True 125 | True 126 | center 127 | none 128 | False 129 | vertical 130 | audio-volume-muted 131 | audio-volume-high 132 | audio-volume-low 133 | audio-volume-medium 134 | 135 | 136 | 137 | + 138 | True 139 | True 140 | none 141 | 142 | 143 | 144 | 145 | - 146 | True 147 | True 148 | none 149 | 150 | 151 | 152 | 153 | False 154 | True 155 | 3 156 | 157 | 158 | 159 | 160 | fullscreen_button 161 | True 162 | True 163 | True 164 | fullscreen_image 165 | none 166 | 0 167 | 0 168 | 169 | 170 | 171 | False 172 | True 173 | 4 174 | 175 | 176 | 177 | 178 | False 179 | True 180 | -1 181 | 182 | 183 | 184 | 185 | title_label 186 | True 187 | False 188 | 5 189 | center 190 | True 191 | 192 | 193 | False 194 | True 195 | 0 196 | 197 | 198 | 199 | 200 | True 201 | False 202 | center 203 | 20 204 | 20 205 | 10 206 | 207 | 208 | True 209 | False 210 | center 211 | center 212 | 5 213 | 214 | 215 | prev_button 216 | True 217 | True 218 | True 219 | center 220 | prev_image 221 | none 222 | 0 223 | 0 224 | 225 | 226 | 227 | False 228 | True 229 | 0 230 | 231 | 232 | 233 | 234 | rewind_button 235 | True 236 | True 237 | True 238 | center 239 | center 240 | rewind_image 241 | none 242 | 0 243 | 0 244 | 245 | 246 | 247 | False 248 | True 249 | 1 250 | 251 | 252 | 253 | 254 | play_pause_button 255 | True 256 | True 257 | True 258 | center 259 | pause_image 260 | none 261 | 0 262 | 0 263 | 264 | 265 | 266 | False 267 | True 268 | 2 269 | 270 | 271 | 272 | 273 | forward_button 274 | True 275 | True 276 | True 277 | center 278 | forward_image 279 | none 280 | 0 281 | 0 282 | 283 | 284 | 285 | False 286 | True 287 | 3 288 | 289 | 290 | 291 | 292 | next_button 293 | True 294 | True 295 | True 296 | center 297 | next_image 298 | none 299 | 0 300 | 0 301 | 302 | 303 | 304 | False 305 | True 306 | 4 307 | 308 | 309 | 310 | 311 | True 312 | True 313 | 0 314 | 315 | 316 | 317 | 318 | rate_label 319 | 40 320 | False 321 | center 322 | 0 323 | 0 324 | right 325 | 326 | 327 | False 328 | True 329 | end 330 | 1 331 | 332 | 333 | 334 | 335 | False 336 | True 337 | 2 338 | 339 | 340 | 341 | 342 | -------------------------------------------------------------------------------- /ios/GstPlay.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/GstPlay.xcodeproj/xcuserdata/slomo.xcuserdatad/xcschemes/GstPlay.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /ios/GstPlay.xcodeproj/xcuserdata/slomo.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | GstPlay.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | AD2B881A198D631B0070367B 16 | 17 | primary 18 | 19 | 20 | AD2B883E198D631B0070367B 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ios/GstPlay/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // GstPlay 4 | // 5 | // Created by Sebastian Dröge on 02/08/14. 6 | // Copyright (c) 2014 Sebastian Dröge. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ios/GstPlay/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // GstPlay 4 | // 5 | // Created by Sebastian Dröge on 02/08/14. 6 | // Copyright (c) 2014 Sebastian Dröge. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | return YES; 16 | } 17 | 18 | - (void)applicationWillResignActive:(UIApplication *)application 19 | { 20 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 21 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 22 | } 23 | 24 | - (void)applicationDidEnterBackground:(UIApplication *)application 25 | { 26 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 27 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 28 | } 29 | 30 | - (void)applicationWillEnterForeground:(UIApplication *)application 31 | { 32 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 33 | } 34 | 35 | - (void)applicationDidBecomeActive:(UIApplication *)application 36 | { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | - (void)applicationWillTerminate:(UIApplication *)application 41 | { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /ios/GstPlay/EaglUIVIew.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #include 4 | #include 5 | 6 | @interface EaglUIView : UIView 7 | { 8 | } 9 | 10 | @end 11 | 12 | -------------------------------------------------------------------------------- /ios/GstPlay/EaglUIVIew.m: -------------------------------------------------------------------------------- 1 | #import "EaglUIVIew.h" 2 | 3 | #import 4 | 5 | @implementation EaglUIView 6 | 7 | 8 | + (Class) layerClass 9 | { 10 | return [CAEAGLLayer class]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ios/GstPlay/GstPlay-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | org.freedesktop.gstreamer.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | MainStoryboard_iPhone 29 | UIMainStoryboardFile~ipad 30 | MainStoryboard_iPad 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /ios/GstPlay/GstPlay-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /ios/GstPlay/LibraryViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface LibraryViewController : UITableViewController 4 | { 5 | NSArray *libraryEntries; 6 | NSArray *mediaEntries; 7 | NSArray *onlineEntries; 8 | } 9 | 10 | - (IBAction)refresh:(id)sender; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /ios/GstPlay/LibraryViewController.m: -------------------------------------------------------------------------------- 1 | #import "LibraryViewController.h" 2 | #import "VideoViewController.h" 3 | #import 4 | 5 | @interface LibraryViewController () 6 | 7 | @end 8 | 9 | @implementation LibraryViewController 10 | 11 | - (void)viewDidLoad 12 | { 13 | [super viewDidLoad]; 14 | [super setTitle:@"Library"]; 15 | [self refreshMediaItems]; 16 | } 17 | 18 | - (IBAction)refresh:(id)sender 19 | { 20 | [self refreshMediaItems]; 21 | [self.tableView reloadData]; 22 | } 23 | 24 | static NSString *CellIdentifier = @"CellIdentifier"; 25 | 26 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 27 | return 3; 28 | } 29 | 30 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 31 | { 32 | switch (section) 33 | { 34 | case 0: return @"Photo library"; 35 | case 1: return @"iTunes file sharing"; 36 | default: return @"Online files"; 37 | } 38 | } 39 | 40 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 41 | switch (section) { 42 | case 0: 43 | return [self->libraryEntries count]; 44 | case 1: 45 | return [self->mediaEntries count]; 46 | case 2: 47 | return [self->onlineEntries count]; 48 | default: 49 | return 0; 50 | } 51 | } 52 | 53 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 54 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 55 | // Configure Cell 56 | UILabel *title = (UILabel *)[cell.contentView viewWithTag:10]; 57 | UILabel *subtitle = (UILabel *)[cell.contentView viewWithTag:11]; 58 | 59 | switch (indexPath.section) { 60 | case 0: subtitle.text = [self->libraryEntries objectAtIndex:indexPath.item]; 61 | break; 62 | case 1: subtitle.text = [self->mediaEntries objectAtIndex:indexPath.item]; 63 | break; 64 | case 2: subtitle.text = [self->onlineEntries objectAtIndex:indexPath.item]; 65 | break; 66 | default: 67 | break; 68 | } 69 | 70 | NSArray *components = [subtitle.text pathComponents]; 71 | title.text = components.lastObject; 72 | 73 | return cell; 74 | } 75 | 76 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 77 | return NO; 78 | } 79 | 80 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 81 | return NO; 82 | } 83 | 84 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 85 | if ([segue.identifier isEqualToString:@"playVideo"]) { 86 | NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; 87 | VideoViewController *destViewController = segue.destinationViewController; 88 | UITableViewCell *cell = [[self tableView] cellForRowAtIndexPath:indexPath]; 89 | UILabel *label = (UILabel *)[cell.contentView viewWithTag:10]; 90 | destViewController.title = label.text; 91 | label = (UILabel *)[cell.contentView viewWithTag:11]; 92 | destViewController.uri = label.text; 93 | } 94 | } 95 | 96 | - (void)refreshMediaItems { 97 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSAllDomainsMask, YES); 98 | NSString *docsPath = [paths objectAtIndex:0]; 99 | 100 | /* Entries from the Photo Library */ 101 | NSMutableArray *entries = [[NSMutableArray alloc] init]; 102 | ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; 103 | [library enumerateGroupsWithTypes:ALAssetsGroupAll 104 | usingBlock:^(ALAssetsGroup *group, BOOL *stop) 105 | { 106 | if (group) { 107 | [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) 108 | { 109 | if(result) { 110 | [entries addObject:[NSString stringWithFormat:@"%@",[result valueForProperty:ALAssetPropertyAssetURL]]]; 111 | *stop = NO; 112 | 113 | } 114 | }]; 115 | } else { 116 | [self.tableView reloadData]; 117 | } 118 | } 119 | failureBlock:^(NSError *error) 120 | { 121 | NSLog(@"ERROR"); 122 | } 123 | ]; 124 | self->libraryEntries = entries; 125 | 126 | /* Retrieve entries from iTunes file sharing */ 127 | entries = [[NSMutableArray alloc] init]; 128 | for (NSString *e in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docsPath error:nil]) 129 | { 130 | [entries addObject:[NSString stringWithFormat:@"file://%@/%@", docsPath, e]]; 131 | } 132 | self->mediaEntries = entries; 133 | self->onlineEntries = [NSArray arrayWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"OnlineMedia" withExtension:@"plist"]]; 134 | } 135 | 136 | @end 137 | -------------------------------------------------------------------------------- /ios/GstPlay/MainStoryboard_iPad.storyboard: -------------------------------------------------------------------------------- 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 | 144 | 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 | 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /ios/GstPlay/MainStoryboard_iPhone.storyboard: -------------------------------------------------------------------------------- 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 | 147 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /ios/GstPlay/OnlineMedia.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_surround-fix.avi 7 | http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_h264.mov 8 | http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_stereo.ogg 9 | http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_stereo.avi 10 | 11 | 12 | http://ftp.nluug.nl/ftp/graphics/blender/apricot/trailer/Sintel_Trailer1.480p.DivX_Plus_HD.mkv 13 | http://ftp.nluug.nl/ftp/graphics/blender/apricot/trailer/sintel_trailer-480p.mp4 14 | http://ftp.nluug.nl/ftp/graphics/blender/apricot/trailer/sintel_trailer-480p.ogv 15 | http://mirrorblender.top-ix.org/movies/sintel-1024-surround.mp4 16 | 17 | 18 | http://blender-mirror.kino3d.org/mango/download.blender.org/demo/movies/ToS/tears_of_steel_720p.mkv 19 | http://blender-mirror.kino3d.org/mango/download.blender.org/demo/movies/ToS/tears_of_steel_720p.mov 20 | http://media.xiph.org/mango/tears_of_steel_1080p.webm 21 | 22 | 23 | http://radio.hbr1.com:19800/trance.ogg 24 | http://radio.hbr1.com:19800/tronic.aac 25 | 26 | 27 | http://non-existing.org/Non_Existing_Server 28 | http://docs.gstreamer.com/Non_Existing_File 29 | 30 | 31 | -------------------------------------------------------------------------------- /ios/GstPlay/Ubuntu-R.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdroege/gst-player/ee3c226c82767a089743e4e06058743e67f73cdb/ios/GstPlay/Ubuntu-R.ttf -------------------------------------------------------------------------------- /ios/GstPlay/VideoViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface VideoViewController : UIViewController { 4 | IBOutlet UIBarButtonItem *play_button; 5 | IBOutlet UIBarButtonItem *pause_button; 6 | IBOutlet UIView *video_view; 7 | IBOutlet UIView *video_container_view; 8 | IBOutlet NSLayoutConstraint *video_width_constraint; 9 | IBOutlet NSLayoutConstraint *video_height_constraint; 10 | IBOutlet UIToolbar *toolbar; 11 | IBOutlet UITextField *time_label; 12 | IBOutlet UISlider *time_slider; 13 | } 14 | 15 | @property (retain,nonatomic) NSString *uri; 16 | 17 | -(IBAction) play:(id)sender; 18 | -(IBAction) pause:(id)sender; 19 | -(IBAction) sliderValueChanged:(id)sender; 20 | -(IBAction) sliderTouchDown:(id)sender; 21 | -(IBAction) sliderTouchUp:(id)sender; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /ios/GstPlay/VideoViewController.m: -------------------------------------------------------------------------------- 1 | #import "VideoViewController.h" 2 | #import 3 | #import 4 | 5 | @interface VideoViewController () { 6 | GstPlayer *player; 7 | int media_width; /* Width of the clip */ 8 | int media_height; /* height ofthe clip */ 9 | Boolean dragging_slider; /* Whether the time slider is being dragged or not */ 10 | Boolean is_local_media; /* Whether this clip is stored locally or is being streamed */ 11 | Boolean is_playing_desired; /* Whether the user asked to go to PLAYING */ 12 | } 13 | 14 | @end 15 | 16 | @implementation VideoViewController 17 | 18 | @synthesize uri; 19 | 20 | /* 21 | * Private methods 22 | */ 23 | 24 | /* The text widget acts as an slave for the seek bar, so it reflects what the seek bar shows, whether 25 | * it is an actual pipeline position or the position the user is currently dragging to. */ 26 | - (void) updateTimeWidget 27 | { 28 | NSInteger position = time_slider.value / 1000; 29 | NSInteger duration = time_slider.maximumValue / 1000; 30 | NSString *position_txt = @" -- "; 31 | NSString *duration_txt = @" -- "; 32 | 33 | if (duration > 0) { 34 | NSUInteger hours = duration / (60 * 60); 35 | NSUInteger minutes = (duration / 60) % 60; 36 | NSUInteger seconds = duration % 60; 37 | 38 | duration_txt = [NSString stringWithFormat:@"%02u:%02u:%02u", hours, minutes, seconds]; 39 | } 40 | if (position > 0) { 41 | NSUInteger hours = position / (60 * 60); 42 | NSUInteger minutes = (position / 60) % 60; 43 | NSUInteger seconds = position % 60; 44 | 45 | position_txt = [NSString stringWithFormat:@"%02u:%02u:%02u", hours, minutes, seconds]; 46 | } 47 | 48 | NSString *text = [NSString stringWithFormat:@"%@ / %@", 49 | position_txt, duration_txt]; 50 | 51 | time_label.text = text; 52 | } 53 | 54 | /* 55 | * Methods from UIViewController 56 | */ 57 | 58 | - (void)viewDidLoad 59 | { 60 | [super viewDidLoad]; 61 | 62 | /* As soon as the GStreamer backend knows the real values, these ones will be replaced */ 63 | media_width = 320; 64 | media_height = 240; 65 | 66 | player = gst_player_new (gst_player_video_overlay_video_renderer_new ((__bridge gpointer)(video_view)), NULL); 67 | g_object_set (player, "uri", [uri UTF8String], NULL); 68 | 69 | gst_debug_set_threshold_for_name("gst-player", GST_LEVEL_TRACE); 70 | 71 | g_signal_connect (player, "position-updated", G_CALLBACK (position_updated), (__bridge gpointer) self); 72 | g_signal_connect (player, "duration-changed", G_CALLBACK (duration_changed), (__bridge gpointer) self); 73 | g_signal_connect (player, "video-dimensions-changed", G_CALLBACK (video_dimensions_changed), (__bridge gpointer) self); 74 | 75 | is_local_media = [uri hasPrefix:@"file://"]; 76 | is_playing_desired = NO; 77 | } 78 | 79 | - (void)viewDidDisappear:(BOOL)animated 80 | { 81 | if (player) 82 | { 83 | gst_object_unref (player); 84 | } 85 | [UIApplication sharedApplication].idleTimerDisabled = NO; 86 | } 87 | 88 | - (void)didReceiveMemoryWarning 89 | { 90 | [super didReceiveMemoryWarning]; 91 | // Dispose of any resources that can be recreated. 92 | } 93 | 94 | /* Called when the Play button is pressed */ 95 | -(IBAction) play:(id)sender 96 | { 97 | gst_player_play (player); 98 | is_playing_desired = YES; 99 | [UIApplication sharedApplication].idleTimerDisabled = YES; 100 | } 101 | 102 | /* Called when the Pause button is pressed */ 103 | -(IBAction) pause:(id)sender 104 | { 105 | gst_player_pause(player); 106 | is_playing_desired = NO; 107 | [UIApplication sharedApplication].idleTimerDisabled = NO; 108 | } 109 | 110 | /* Called when the time slider position has changed, either because the user dragged it or 111 | * we programmatically changed its position. dragging_slider tells us which one happened */ 112 | - (IBAction)sliderValueChanged:(id)sender { 113 | if (!dragging_slider) return; 114 | // If this is a local file, allow scrub seeking, this is, seek as soon as the slider is moved. 115 | if (is_local_media) 116 | gst_player_seek (player, time_slider.value * 1000000); 117 | [self updateTimeWidget]; 118 | } 119 | 120 | /* Called when the user starts to drag the time slider */ 121 | - (IBAction)sliderTouchDown:(id)sender { 122 | gst_player_pause (player); 123 | dragging_slider = YES; 124 | } 125 | 126 | /* Called when the user stops dragging the time slider */ 127 | - (IBAction)sliderTouchUp:(id)sender { 128 | dragging_slider = NO; 129 | // If this is a remote file, scrub seeking is probably not going to work smoothly enough. 130 | // Therefore, perform only the seek when the slider is released. 131 | if (!is_local_media) 132 | gst_player_seek (player, ((long)time_slider.value) * 1000000); 133 | if (is_playing_desired) 134 | gst_player_play (player); 135 | } 136 | 137 | /* Called when the size of the main view has changed, so we can 138 | * resize the sub-views in ways not allowed by storyboarding. */ 139 | - (void)viewDidLayoutSubviews 140 | { 141 | CGFloat view_width = video_container_view.bounds.size.width; 142 | CGFloat view_height = video_container_view.bounds.size.height; 143 | 144 | CGFloat correct_height = view_width * media_height / media_width; 145 | CGFloat correct_width = view_height * media_width / media_height; 146 | 147 | if (correct_height < view_height) { 148 | video_height_constraint.constant = correct_height; 149 | video_width_constraint.constant = view_width; 150 | } else { 151 | video_width_constraint.constant = correct_width; 152 | video_height_constraint.constant = view_height; 153 | } 154 | 155 | time_slider.frame = CGRectMake(time_slider.frame.origin.x, time_slider.frame.origin.y, toolbar.frame.size.width - time_slider.frame.origin.x - 8, time_slider.frame.size.height); 156 | } 157 | 158 | static void video_dimensions_changed (GstPlayer * unused, gint width, gint height, VideoViewController * self) 159 | { 160 | dispatch_async(dispatch_get_main_queue(), ^{ 161 | if (width > 0 && height > 0) { 162 | [self videoDimensionsChanged:width height:height]; 163 | } 164 | }); 165 | } 166 | 167 | -(void) videoDimensionsChanged:(NSInteger)width height:(NSInteger)height 168 | { 169 | media_width = width; 170 | media_height = height; 171 | [self viewDidLayoutSubviews]; 172 | [video_view setNeedsLayout]; 173 | [video_view layoutIfNeeded]; 174 | } 175 | 176 | static void position_updated (GstPlayer * unused, GstClockTime position, VideoViewController *self) 177 | { 178 | dispatch_async(dispatch_get_main_queue(), ^{ 179 | [self positionUpdated:(int) (position / 1000000)]; 180 | }); 181 | } 182 | 183 | -(void) positionUpdated:(NSInteger)position 184 | { 185 | /* Ignore messages from the pipeline if the time sliders is being dragged */ 186 | if (dragging_slider) return; 187 | 188 | time_slider.value = position; 189 | [self updateTimeWidget]; 190 | } 191 | 192 | static void duration_changed (GstPlayer * unused, GstClockTime duration, VideoViewController *self) 193 | { 194 | dispatch_async(dispatch_get_main_queue(), ^{ 195 | [self durationChanged:(int) (duration / 1000000)]; 196 | }); 197 | } 198 | 199 | -(void) durationChanged:(NSInteger)duration 200 | { 201 | time_slider.maximumValue = duration; 202 | [self updateTimeWidget]; 203 | } 204 | 205 | @end 206 | -------------------------------------------------------------------------------- /ios/GstPlay/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ios/GstPlay/fonts.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | mono 20 | 21 | 22 | monospace 23 | 24 | 25 | 26 | 29 | 30 | 31 | sans serif 32 | 33 | 34 | sans-serif 35 | 36 | 37 | 38 | 41 | 42 | 43 | sans 44 | 45 | 46 | sans-serif 47 | 48 | 49 | 50 | 51 | 56 | 57 | 0x0020 58 | 0x00A0 59 | 0x00AD 60 | 0x034F 61 | 0x0600 62 | 0x0601 63 | 0x0602 64 | 0x0603 65 | 0x06DD 66 | 0x070F 67 | 0x115F 68 | 0x1160 69 | 0x1680 70 | 0x17B4 71 | 0x17B5 72 | 0x180E 73 | 0x2000 74 | 0x2001 75 | 0x2002 76 | 0x2003 77 | 0x2004 78 | 0x2005 79 | 0x2006 80 | 0x2007 81 | 0x2008 82 | 0x2009 83 | 0x200A 84 | 0x200B 85 | 0x200C 86 | 0x200D 87 | 0x200E 88 | 0x200F 89 | 0x2028 90 | 0x2029 91 | 0x202A 92 | 0x202B 93 | 0x202C 94 | 0x202D 95 | 0x202E 96 | 0x202F 97 | 0x205F 98 | 0x2060 99 | 0x2061 100 | 0x2062 101 | 0x2063 102 | 0x206A 103 | 0x206B 104 | 0x206C 105 | 0x206D 106 | 0x206E 107 | 0x206F 108 | 0x2800 109 | 0x3000 110 | 0x3164 111 | 0xFEFF 112 | 0xFFA0 113 | 0xFFF9 114 | 0xFFFA 115 | 0xFFFB 116 | 117 | 120 | 121 | 30 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /ios/GstPlay/gst_ios_init.h: -------------------------------------------------------------------------------- 1 | #ifndef __GST_IOS_INIT_H__ 2 | #define __GST_IOS_INIT_H__ 3 | 4 | #include 5 | 6 | G_BEGIN_DECLS 7 | 8 | #define GST_G_IO_MODULE_DECLARE(name) \ 9 | extern void G_PASTE(g_io_module_, G_PASTE(name, _load_static)) (void) 10 | 11 | #define GST_G_IO_MODULE_LOAD(name) \ 12 | G_PASTE(g_io_module_, G_PASTE(name, _load_static)) () 13 | 14 | /* Uncomment each line to enable the plugin categories that your application needs. 15 | * You can also enable individual plugins. See gst_ios_init.c to see their names 16 | */ 17 | 18 | //#define GST_IOS_PLUGINS_GES 19 | #define GST_IOS_PLUGINS_CORE 20 | //#define GST_IOS_PLUGINS_CAPTURE 21 | #define GST_IOS_PLUGINS_CODECS_RESTRICTED 22 | //#define GST_IOS_PLUGINS_ENCODING 23 | #define GST_IOS_PLUGINS_CODECS_GPL 24 | #define GST_IOS_PLUGINS_NET_RESTRICTED 25 | #define GST_IOS_PLUGINS_SYS 26 | #define GST_IOS_PLUGINS_VIS 27 | #define GST_IOS_PLUGINS_PLAYBACK 28 | #define GST_IOS_PLUGINS_EFFECTS 29 | #define GST_IOS_PLUGINS_CODECS 30 | #define GST_IOS_PLUGINS_NET 31 | 32 | 33 | #define GST_IOS_GIO_MODULE_GNUTLS 34 | 35 | void gst_ios_init (); 36 | 37 | G_END_DECLS 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ios/GstPlay/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | #include "gst_ios_init.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | @autoreleasepool { 9 | gst_ios_init(); 10 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ios/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = \ 2 | GstPlay/AppDelegate.h \ 3 | GstPlay/AppDelegate.m \ 4 | GstPlay/EaglUIVIew.h \ 5 | GstPlay/EaglUIVIew.m \ 6 | GstPlay/en.lproj/InfoPlist.strings \ 7 | GstPlay/fonts.conf \ 8 | GstPlay/gst_ios_init.h \ 9 | GstPlay/gst_ios_init.m \ 10 | GstPlay/GstPlay-Info.plist \ 11 | GstPlay/GstPlay-Prefix.pch \ 12 | GstPlay/LibraryViewController.h \ 13 | GstPlay/LibraryViewController.m \ 14 | GstPlay/main.m \ 15 | GstPlay/MainStoryboard_iPad.storyboard \ 16 | GstPlay/MainStoryboard_iPhone.storyboard \ 17 | GstPlay/Ubuntu-R.ttf \ 18 | GstPlay/VideoViewController.h \ 19 | GstPlay/VideoViewController.m \ 20 | GstPlay.xcodeproj/project.xcworkspace/contents.xcworkspacedata \ 21 | GstPlay.xcodeproj/project.pbxproj 22 | 23 | -------------------------------------------------------------------------------- /qt/deployment.pri: -------------------------------------------------------------------------------- 1 | android-no-sdk { 2 | target.path = /data/user/qt 3 | export(target.path) 4 | INSTALLS += target 5 | } else:android { 6 | x86 { 7 | target.path = /libs/x86 8 | } else: armeabi-v7a { 9 | target.path = /libs/armeabi-v7a 10 | } else { 11 | target.path = /libs/armeabi 12 | } 13 | export(target.path) 14 | INSTALLS += target 15 | } else:unix { 16 | isEmpty(target.path) { 17 | qnx { 18 | target.path = /tmp/$${TARGET}/bin 19 | } else { 20 | target.path = /opt/$${TARGET}/bin 21 | } 22 | export(target.path) 23 | } 24 | INSTALLS += target 25 | } 26 | 27 | export(INSTALLS) 28 | -------------------------------------------------------------------------------- /qt/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdroege/gst-player/ee3c226c82767a089743e4e06058743e67f73cdb/qt/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /qt/fontawesome-webfont.ttf.txt: -------------------------------------------------------------------------------- 1 | 2 | Font Awesome 3 | 4 | URL: http://fontawesome.io 5 | 6 | Font License 7 | 8 | License: SIL OFL 1.1 9 | URL: http://scripts.sil.org/OFL 10 | 11 | -------------------------------------------------------------------------------- /qt/fontawesome.js: -------------------------------------------------------------------------------- 1 | var Icon = { 2 | Glass : "\uf000", 3 | Music : "\uf001", 4 | Search : "\uf002", 5 | Envelope : "\uf003", 6 | Heart : "\uf004", 7 | Star : "\uf005", 8 | StarEmpty : "\uf006", 9 | User : "\uf007", 10 | Film : "\uf008", 11 | ThLarge : "\uf009", 12 | Th : "\uf00a", 13 | ThList : "\uf00b", 14 | Ok : "\uf00c", 15 | Remove : "\uf00d", 16 | ZoomIn : "\uf00e", 17 | ZoomOut : "\uf010", 18 | Off : "\uf011", 19 | Signal : "\uf012", 20 | Cog : "\uf013", 21 | Trash : "\uf014", 22 | Home : "\uf015", 23 | File : "\uf016", 24 | Time : "\uf017", 25 | Road : "\uf018", 26 | DownloadAlt : "\uf019", 27 | Download : "\uf01a", 28 | Upload : "\uf01b", 29 | Inbox : "\uf01c", 30 | PlayCircle : "\uf01d", 31 | Repeat : "\uf01e", 32 | Refresh : "\uf021", 33 | ListAlt : "\uf022", 34 | Lock : "\uf023", 35 | Flag : "\uf024", 36 | Headphones : "\uf025", 37 | VolumeOff : "\uf026", 38 | VolumeDown : "\uf027", 39 | VolumeUp : "\uf028", 40 | Qrcode : "\uf029", 41 | Barcode : "\uf02a", 42 | Tag : "\uf02b", 43 | Tags : "\uf02c", 44 | Book : "\uf02d", 45 | Bookmark : "\uf02e", 46 | Print : "\uf02f", 47 | Camera : "\uf030", 48 | Font : "\uf031", 49 | Bold : "\uf032", 50 | Italic : "\uf033", 51 | TextHeight : "\uf034", 52 | TextWidth : "\uf035", 53 | AlignLeft : "\uf036", 54 | AlignCenter : "\uf037", 55 | AlignRight : "\uf038", 56 | AlignJustify : "\uf039", 57 | List : "\uf03a", 58 | IndentLeft : "\uf03b", 59 | IndentRight : "\uf03c", 60 | FacetimeVideo : "\uf03d", 61 | Picture : "\uf03e", 62 | Pencil : "\uf040", 63 | MapMarker : "\uf041", 64 | Adjust : "\uf042", 65 | Tint : "\uf043", 66 | Edit : "\uf044", 67 | Share : "\uf045", 68 | Check : "\uf046", 69 | Move : "\uf047", 70 | StepBackward : "\uf048", 71 | StepForward : "\uf049", 72 | Backward : "\uf04a", 73 | Play : "\uf04b", 74 | Pause : "\uf04c", 75 | Stop : "\uf04d", 76 | Forward : "\uf04e", 77 | FastForward : "\uf050", 78 | StepForward : "\uf051", 79 | Eject : "\uf052", 80 | ChevronLeft : "\uf053", 81 | ChevronRight : "\uf054", 82 | PlusSign : "\uf055", 83 | MinusSign : "\uf056", 84 | RemoveSign : "\uf057", 85 | OkSign : "\uf058", 86 | QuestionSign : "\uf059", 87 | InfoSign : "\uf05a", 88 | Screenshot : "\uf05b", 89 | RemoveCircle : "\uf05c", 90 | OkCircle : "\uf05d", 91 | BanCircle : "\uf05e", 92 | ArrowLeft : "\uf060", 93 | ArrowRight : "\uf061", 94 | ArrowUp : "\uf062", 95 | ArrowDown : "\uf063", 96 | ShareAlt : "\uf064", 97 | ResizeFull : "\uf065", 98 | ResizeSmall : "\uf066", 99 | Plus : "\uf067", 100 | Minus : "\uf068", 101 | Asterish : "\uf069", 102 | ExclamationSign : "\uf06a", 103 | Gift : "\uf06b", 104 | Leave : "\uf06c", 105 | Fire : "\uf06d", 106 | EyeOpen : "\uf06e", 107 | EyeClose : "\uf070", 108 | WarningSign : "\uf071", 109 | Plane : "\uf072", 110 | Calendar : "\uf073", 111 | Random : "\uf074", 112 | Comment : "\uf075", 113 | Magnet : "\uf076", 114 | ChevronUp : "\uf077", 115 | ChevronDown : "\uf078", 116 | Retweet : "\uf079", 117 | ShoppingCart : "\uf07a", 118 | FolderClose : "\uf07b", 119 | FolderOpen : "\uf07c", 120 | ResizeVertical : "\uf07d", 121 | ResizeHorizontal : "\uf07e", 122 | BarChart : "\uf080", 123 | TwitterSign : "\uf081", 124 | FacebookSign : "\uf082", 125 | CameraRetro : "\uf083", 126 | Key : "\uf084", 127 | Cogs : "\uf085", 128 | Comments : "\uf086", 129 | ThumbsUp : "\uf087", 130 | ThumbsDown : "\uf088", 131 | StarHalf : "\uf089", 132 | HeartEmpty : "\uf08a", 133 | Signout : "\uf08b", 134 | LinkedinSign : "\uf08c", 135 | Pushpin : "\uf08d", 136 | ExternalLink : "\uf08e", 137 | Signin : "\uf090", 138 | Trophy : "\uf091", 139 | GithubSign : "\uf092", 140 | UploadAlt : "\uf093", 141 | Lemon : "\uf094", 142 | Phone : "\uf095", 143 | CheckEmpty : "\uf096", 144 | BookmarkEmpty : "\uf097", 145 | PhoneSign : "\uf098", 146 | Twitter : "\uf099", 147 | Facebook : "\uf09a", 148 | Github : "\uf09b", 149 | Unlock : "\uf09c", 150 | CreditCard : "\uf09d", 151 | Rss : "\uf09e", 152 | Hdd : "\uf0a0", 153 | Bullhorn : "\uf0a1", 154 | Bell : "\uf0a2", 155 | Certificate : "\uf0a3", 156 | HandRight : "\uf0a4", 157 | HandLeft : "\uf0a5", 158 | HandUp : "\uf0a6", 159 | HandDown : "\uf0a7", 160 | CircleArrowLeft : "\uf0a8", 161 | CircleArrowRight : "\uf0a9", 162 | CircleArrowUp : "\uf0aa", 163 | CircleArrowDown : "\uf0ab", 164 | Globe : "\uf0ac", 165 | Wrench : "\uf0ad", 166 | Tasks : "\uf0ae", 167 | Filter : "\uf0b0", 168 | Briefcase : "\uf0b1", 169 | Fullscreen : "\uf0b2", 170 | Group : "\uf0c0", 171 | Link : "\uf0c1", 172 | Cloud : "\uf0c2", 173 | Beaker : "\uf0c3", 174 | Cut : "\uf0c4", 175 | Copy : "\uf0c5", 176 | PaperClip : "\uf0c6", 177 | Save : "\uf0c7", 178 | SignBlank : "\uf0c8", 179 | Reorder : "\uf0c9", 180 | ListUl : "\uf0ca", 181 | ListOl : "\uf0cb", 182 | Strikethrough : "\uf0cc", 183 | Underline : "\uf0cd", 184 | Table : "\uf0ce", 185 | Magic : "\uf0d0", 186 | Truck : "\uf0d1", 187 | Pinterest : "\uf0d2", 188 | PinterestSign : "\uf0d3", 189 | GooglePlusSign : "\uf0d4", 190 | GooglePlus : "\uf0d5", 191 | Money : "\uf0d6", 192 | CaretDown : "\uf0d7", 193 | CaretUp : "\uf0d8", 194 | CaretLeft : "\uf0d9", 195 | CaretRight : "\uf0da", 196 | Columns : "\uf0db", 197 | Sort : "\uf0dc", 198 | SortDown : "\uf0dd", 199 | SortUp : "\uf0de", 200 | EnvelopeAlt : "\uf0e0", 201 | Linkedin : "\uf0e1", 202 | Undo : "\uf0e2", 203 | Legal : "\uf0e3", 204 | Dashboard : "\uf0e4", 205 | CommentAlt : "\uf0e5", 206 | CommentsAlt : "\uf0e6", 207 | Bolt : "\uf0e7", 208 | Sitemap : "\uf0e8", 209 | Unbrella : "\uf0e9", 210 | Paste : "\uf0ea", 211 | ClosedCaptions : "\uf20a", 212 | UserMd : "\uf200", 213 | }; 214 | 215 | -------------------------------------------------------------------------------- /qt/imagesample.cpp: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2015 Alexandre Moreno 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #include 22 | #include "imagesample.h" 23 | 24 | ImageSample::ImageSample() 25 | : QQuickPaintedItem() 26 | , sample_() 27 | { 28 | 29 | } 30 | 31 | ImageSample::~ImageSample() 32 | { 33 | 34 | } 35 | 36 | void ImageSample::paint(QPainter *painter) 37 | { 38 | if (sample_.size().isEmpty()) 39 | return; 40 | 41 | float aspect_ratio = sample_.width() / sample_.height(); 42 | int w = height() * aspect_ratio; 43 | int x = (width() - w) / 2; 44 | 45 | painter->setViewport(x, 0, w, height()); 46 | painter->drawImage(QRectF(0, 0, width(), height()), sample_); 47 | } 48 | 49 | const QImage &ImageSample::sample() const 50 | { 51 | return sample_; 52 | } 53 | 54 | void ImageSample::setSample(const QImage &sample) 55 | { 56 | sample_ = sample; 57 | update(); 58 | } 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /qt/imagesample.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2015 Alexandre Moreno 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef IMAGESAMPLE_H 22 | #define IMAGESAMPLE_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "player.h" 29 | 30 | class ImageSample : public QQuickPaintedItem 31 | { 32 | Q_OBJECT 33 | Q_PROPERTY(QImage sample READ sample WRITE setSample) 34 | public: 35 | ImageSample(); 36 | ~ImageSample(); 37 | void paint(QPainter *painter); 38 | 39 | const QImage &sample() const; 40 | void setSample(const QImage &sample); 41 | 42 | private: 43 | QImage sample_; 44 | }; 45 | 46 | #endif // IMAGESAMPLE_H 47 | -------------------------------------------------------------------------------- /qt/main.cpp: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2015 Alexandre Moreno 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "player.h" 28 | #include "imagesample.h" 29 | 30 | int main(int argc, char *argv[]) 31 | { 32 | QGuiApplication app(argc, argv); 33 | int result; 34 | 35 | QCommandLineParser parser; 36 | parser.setApplicationDescription("GstPlayer"); 37 | parser.addHelpOption(); 38 | parser.addPositionalArgument("urls", 39 | QCoreApplication::translate("main", "URLs to play, optionally."), "[urls...]"); 40 | parser.process(app); 41 | 42 | QList media_files; 43 | 44 | const QStringList args = parser.positionalArguments(); 45 | foreach (const QString file, args) { 46 | media_files << QUrl::fromUserInput(file); 47 | } 48 | 49 | qmlRegisterType("Player", 1, 0, "Player"); 50 | qmlRegisterType("ImageSample", 1, 0, "ImageSample"); 51 | 52 | /* the plugin must be loaded before loading the qml file to register the 53 | * GstGLVideoItem qml item 54 | * FIXME Add a QQmlExtensionPlugin into qmlglsink to register GstGLVideoItem 55 | * with the QML engine, then remove this */ 56 | gst_init(NULL,NULL); 57 | GstElement *sink = gst_element_factory_make ("qmlglsink", NULL); 58 | gst_object_unref(sink); 59 | 60 | 61 | QQmlApplicationEngine engine; 62 | engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 63 | 64 | QObject *rootObject = engine.rootObjects().first(); 65 | 66 | Player *player = rootObject->findChild("player"); 67 | 68 | QQuickItem *videoItem = rootObject->findChild("videoItem"); 69 | player->setVideoOutput(videoItem); 70 | 71 | if (!media_files.isEmpty()) 72 | player->setPlaylist(media_files); 73 | 74 | result = app.exec(); 75 | 76 | gst_deinit (); 77 | return result; 78 | } 79 | -------------------------------------------------------------------------------- /qt/play.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT += qml quick widgets 4 | 5 | CONFIG += c++11 6 | 7 | DEFINES += GST_USE_UNSTABLE_API 8 | 9 | RESOURCES += qml.qrc 10 | 11 | # Additional import path used to resolve QML modules in Qt Creator's code model 12 | QML_IMPORT_PATH = 13 | 14 | # Default rules for deployment. 15 | include(deployment.pri) 16 | 17 | # not tested (yet) 18 | unix:!macx { 19 | QT_CONFIG -= no-pkg-config 20 | CONFIG += link_pkgconfig 21 | PKGCONFIG = \ 22 | gstreamer-1.0 \ 23 | gstreamer-player-1.0 \ 24 | gstreamer-tag-1.0 25 | } 26 | 27 | macx { 28 | QMAKE_MAC_SDK = macosx10.9 29 | INCLUDEPATH += /Library/Frameworks/GStreamer.framework/Headers 30 | 31 | LIBS += \ 32 | -framework AppKit \ 33 | -F/Library/Frameworks -framework GStreamer 34 | } 35 | 36 | HEADERS += \ 37 | qgstplayer.h \ 38 | player.h \ 39 | quickrenderer.h \ 40 | imagesample.h 41 | 42 | SOURCES += main.cpp \ 43 | qgstplayer.cpp \ 44 | player.cpp \ 45 | quickrenderer.cpp \ 46 | imagesample.cpp 47 | 48 | DISTFILES += 49 | -------------------------------------------------------------------------------- /qt/player.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* GStreamer 3 | * 4 | * Copyright (C) 2015 Alexandre Moreno 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 19 | * Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | #include "player.h" 23 | #include "quickrenderer.h" 24 | 25 | Player::Player(QObject *parent) 26 | : Player(parent, new QuickRenderer) 27 | { 28 | 29 | } 30 | 31 | Player::Player(QObject *parent, QuickRenderer *renderer) 32 | : QGstPlayer::Player(parent, renderer) 33 | , renderer_(renderer) 34 | { 35 | renderer_->setParent(this); 36 | } 37 | 38 | void Player::setVideoOutput(QQuickItem *output) 39 | { 40 | renderer_->setVideoItem(output); 41 | } 42 | -------------------------------------------------------------------------------- /qt/player.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2015 Alexandre Moreno 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef PLAYER_H 22 | #define PLAYER_H 23 | 24 | #include 25 | #include 26 | #include "qgstplayer.h" 27 | 28 | class QuickRenderer; 29 | 30 | class Player : public QGstPlayer::Player 31 | { 32 | Q_OBJECT 33 | public: 34 | Player(QObject *parent = 0); 35 | void setVideoOutput(QQuickItem *output); 36 | 37 | private: 38 | Player(QObject *parent, QuickRenderer *renderer); 39 | QuickRenderer *renderer_; 40 | }; 41 | 42 | Q_DECLARE_METATYPE(Player*) 43 | 44 | #endif // PLAYER_H 45 | -------------------------------------------------------------------------------- /qt/qgstplayer.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2015 Alexandre Moreno 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef QGSTPLAYER_H 22 | #define QGSTPLAYER_H 23 | 24 | #include 25 | #include 26 | #include 27 | //#include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace QGstPlayer { 34 | 35 | class VideoRenderer; 36 | class MediaInfo; 37 | class StreamInfo; 38 | class VideInfo; 39 | class AudioInfo; 40 | class SubtitleInfo; 41 | 42 | class Player : public QObject 43 | { 44 | Q_OBJECT 45 | Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) 46 | Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) 47 | Q_PROPERTY(qint64 position READ position NOTIFY positionUpdated) 48 | Q_PROPERTY(quint32 positionUpdateInterval READ positionUpdateInterval 49 | WRITE setPositionUpdateInterval) 50 | Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged) 51 | Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) 52 | Q_PROPERTY(int buffering READ buffering NOTIFY bufferingChanged) 53 | Q_PROPERTY(QSize resolution READ resolution WRITE setResolution NOTIFY resolutionChanged) 54 | Q_PROPERTY(State state READ state NOTIFY stateChanged) 55 | Q_PROPERTY(QObject *mediaInfo READ mediaInfo NOTIFY mediaInfoChanged) 56 | Q_PROPERTY(bool videoAvailable READ isVideoAvailable NOTIFY videoAvailableChanged) 57 | Q_PROPERTY(QVariant currentVideo READ currentVideo WRITE setCurrentVideo) 58 | Q_PROPERTY(QVariant currentAudio READ currentAudio WRITE setCurrentAudio) 59 | Q_PROPERTY(QVariant currentSubtitle READ currentSubtitle WRITE setCurrentSubtitle) 60 | Q_PROPERTY(bool subtitleEnabled READ isSubtitleEnabled WRITE setSubtitleEnabled 61 | NOTIFY subtitleEnabledChanged) 62 | Q_PROPERTY(bool autoPlay READ autoPlay WRITE setAutoPlay) 63 | Q_PROPERTY(QList playlist READ playlist WRITE setPlaylist) 64 | 65 | Q_ENUMS(State) 66 | 67 | public: 68 | explicit Player(QObject *parent = 0, VideoRenderer *renderer = 0); 69 | virtual ~Player(); 70 | 71 | typedef GstPlayerError Error; 72 | enum State { 73 | STOPPED = GST_PLAYER_STATE_STOPPED, 74 | BUFFERING = GST_PLAYER_STATE_BUFFERING, 75 | PAUSED = GST_PLAYER_STATE_PAUSED, 76 | PLAYING = GST_PLAYER_STATE_PLAYING 77 | }; 78 | 79 | QUrl source() const; 80 | qint64 duration() const; 81 | qint64 position() const; 82 | qreal volume() const; 83 | bool isMuted() const; 84 | int buffering() const; 85 | State state() const; 86 | GstElement *pipeline() const; 87 | QSize resolution() const; 88 | void setResolution(QSize size); 89 | bool isVideoAvailable() const; 90 | MediaInfo *mediaInfo() const; 91 | QVariant currentVideo() const; 92 | QVariant currentAudio() const; 93 | QVariant currentSubtitle() const; 94 | bool isSubtitleEnabled() const; 95 | quint32 positionUpdateInterval() const; 96 | bool autoPlay() const; 97 | QList playlist() const; 98 | 99 | signals: 100 | void stateChanged(State new_state); 101 | void bufferingChanged(int percent); 102 | void endOfStream(); 103 | void positionUpdated(qint64 new_position); 104 | void durationChanged(qint64 duration); 105 | void resolutionChanged(QSize resolution); 106 | void volumeChanged(qreal volume); 107 | void mutedChanged(bool muted); 108 | void mediaInfoChanged(); 109 | void sourceChanged(QUrl new_url); 110 | void videoAvailableChanged(bool videoAvailable); 111 | void subtitleEnabledChanged(bool enabled); 112 | 113 | public slots: 114 | void play(); 115 | void pause(); 116 | void stop(); 117 | void seek(qint64 position); 118 | void setSource(QUrl const& url); 119 | void setVolume(qreal val); 120 | void setMuted(bool val); 121 | void setPosition(qint64 pos); 122 | void setCurrentVideo(QVariant track); 123 | void setCurrentAudio(QVariant track); 124 | void setCurrentSubtitle(QVariant track); 125 | void setSubtitleEnabled(bool enabled); 126 | void setPositionUpdateInterval(quint32 interval); 127 | void setPlaylist(const QList &playlist); 128 | void next(); 129 | void previous(); 130 | void setAutoPlay(bool auto_play); 131 | 132 | private: 133 | Q_DISABLE_COPY(Player) 134 | static void onStateChanged(Player *, GstPlayerState state); 135 | static void onPositionUpdated(Player *, GstClockTime position); 136 | static void onDurationChanged(Player *, GstClockTime duration); 137 | static void onBufferingChanged(Player *, int percent); 138 | static void onVideoDimensionsChanged(Player *, int w, int h); 139 | static void onVolumeChanged(Player *); 140 | static void onMuteChanged(Player *); 141 | static void onMediaInfoUpdated(Player *, GstPlayerMediaInfo *media_info); 142 | static void onEndOfStreamReached(Player *); 143 | 144 | void setUri(QUrl url); 145 | 146 | GstPlayer *player_; 147 | State state_; 148 | QSize videoDimensions_; 149 | MediaInfo *mediaInfo_; 150 | bool videoAvailable_; 151 | bool subtitleEnabled_; 152 | bool autoPlay_; 153 | QList playlist_; 154 | QList::iterator iter_; 155 | }; 156 | 157 | class VideoRenderer 158 | { 159 | public: 160 | GstPlayerVideoRenderer *renderer(); 161 | virtual GstElement *createVideoSink() = 0; 162 | protected: 163 | VideoRenderer(); 164 | virtual ~VideoRenderer(); 165 | private: 166 | GstPlayerVideoRenderer *renderer_; 167 | }; 168 | 169 | class MediaInfo : public QObject 170 | { 171 | Q_OBJECT 172 | Q_PROPERTY(QString uri READ uri NOTIFY uriChanged) 173 | Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged) 174 | Q_PROPERTY(QString title READ title NOTIFY titleChanged) 175 | Q_PROPERTY(QList videoStreams READ videoStreams CONSTANT) 176 | Q_PROPERTY(QList audioStreams READ audioStreams CONSTANT) 177 | Q_PROPERTY(QList subtitleStreams READ subtitleStreams CONSTANT) 178 | Q_PROPERTY(QImage sample READ sample NOTIFY sampleChanged) 179 | 180 | public: 181 | explicit MediaInfo(Player *player = 0); 182 | QString uri() const; 183 | QString title() const; 184 | bool isSeekable() const; 185 | const QList &videoStreams() const; 186 | const QList &audioStreams() const; 187 | const QList &subtitleStreams() const; 188 | const QImage &sample(); 189 | 190 | signals: 191 | void uriChanged(); 192 | void seekableChanged(); 193 | void titleChanged(); 194 | void sampleChanged(); 195 | 196 | public Q_SLOTS: 197 | void update(GstPlayerMediaInfo *info); 198 | private: 199 | QString uri_; 200 | QString title_; 201 | bool isSeekable_; 202 | QList videoStreams_; 203 | QList audioStreams_; 204 | QList subtitleStreams_; 205 | QImage sample_; 206 | }; 207 | 208 | class StreamInfo : public QObject 209 | { 210 | Q_OBJECT 211 | Q_PROPERTY(int index READ index CONSTANT) 212 | public: 213 | int index() const; 214 | 215 | protected: 216 | StreamInfo(GstPlayerStreamInfo* info); 217 | private: 218 | GstPlayerStreamInfo *stream_; 219 | int index_; 220 | }; 221 | 222 | class VideoInfo : public StreamInfo 223 | { 224 | Q_OBJECT 225 | Q_PROPERTY(QSize resolution READ resolution CONSTANT) 226 | public: 227 | VideoInfo(GstPlayerVideoInfo *info); 228 | QSize resolution() const; 229 | 230 | private: 231 | GstPlayerVideoInfo *video_; 232 | QSize resolution_; 233 | }; 234 | 235 | class AudioInfo : public StreamInfo 236 | { 237 | Q_OBJECT 238 | Q_PROPERTY(QString language READ language CONSTANT) 239 | Q_PROPERTY(int channels READ channels CONSTANT) 240 | Q_PROPERTY(int bitRate READ bitRate CONSTANT) 241 | Q_PROPERTY(int sampleRate READ sampleRate CONSTANT) 242 | 243 | public: 244 | AudioInfo(GstPlayerAudioInfo *info); 245 | QString const& language() const; 246 | int channels() const; 247 | int bitRate() const; 248 | int sampleRate() const; 249 | 250 | private: 251 | GstPlayerAudioInfo *audio_; 252 | QString language_; 253 | int channels_; 254 | int bitRate_; 255 | int sampleRate_; 256 | }; 257 | 258 | class SubtitleInfo : public StreamInfo 259 | { 260 | Q_OBJECT 261 | Q_PROPERTY(QString language READ language CONSTANT) 262 | public: 263 | SubtitleInfo(GstPlayerSubtitleInfo *info); 264 | QString const& language() const; 265 | 266 | private: 267 | GstPlayerSubtitleInfo *subtitle_; 268 | QString language_; 269 | }; 270 | 271 | } 272 | 273 | Q_DECLARE_METATYPE(QGstPlayer::Player*) 274 | Q_DECLARE_METATYPE(QGstPlayer::Player::State) 275 | Q_DECLARE_METATYPE(QGstPlayer::MediaInfo*) 276 | 277 | extern "C" { 278 | 279 | typedef struct _GstPlayerQtVideoRenderer 280 | GstPlayerQtVideoRenderer; 281 | 282 | typedef struct _GstPlayerQtVideoRendererClass 283 | GstPlayerQtVideoRendererClass; 284 | 285 | #define GST_TYPE_PLAYER_QT_VIDEO_RENDERER (gst_player_qt_video_renderer_get_type ()) 286 | #define GST_IS_PLAYER_QT_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PLAYER_QT_VIDEO_RENDERER)) 287 | #define GST_IS_PLAYER_QT_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAYER_QT_VIDEO_RENDERER)) 288 | #define GST_PLAYER_QT_VIDEO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PLAYER_QT_VIDEO_RENDERER, GstPlayerQtVideoRendererClass)) 289 | #define GST_PLAYER_QT_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PLAYER_QT_VIDEO_RENDERER, GstPlayerQtVideoRenderer)) 290 | #define GST_PLAYER_QT_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PLAYER_QT_VIDEO_RENDERER, GstPlayerQtVideoRendererClass)) 291 | #define GST_PLAYER_QT_VIDEO_RENDERER_CAST(obj) ((GstPlayerQtVideoRenderer*)(obj)) 292 | 293 | GType gst_player_qt_video_renderer_get_type (void); 294 | 295 | typedef struct _GstPlayerQtSignalDispatcher 296 | GstPlayerQtSignalDispatcher; 297 | 298 | typedef struct _GstPlayerQtSignalDispatcherClass 299 | GstPlayerQtSignalDispatcherClass; 300 | 301 | #define GST_TYPE_PLAYER_QT_SIGNAL_DISPATCHER (gst_player_qt_signal_dispatcher_get_type ()) 302 | #define GST_IS_PLAYER_QT_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PLAYER_QT_SIGNAL_DISPATCHER)) 303 | #define GST_IS_PLAYER_QT_SIGNAL_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAYER_QT_SIGNAL_DISPATCHER)) 304 | #define GST_PLAYER_QT_SIGNAL_DISPATCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PLAYER_QT_SIGNAL_DISPATCHER, GstPlayerQtSignalDispatcherClass)) 305 | #define GST_PLAYER_QT_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PLAYER_QT_SIGNAL_DISPATCHER, GstPlayerQtSignalDispatcher)) 306 | #define GST_PLAYER_QT_SIGNAL_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PLAYER_QT_SIGNAL_DISPATCHER, GstPlayerQtSignalDispatcherClass)) 307 | #define GST_PLAYER_QT_SIGNAL_DISPATCHER_CAST(obj) ((GstPlayerQtSignalDispatcher*)(obj)) 308 | 309 | GType gst_player_qt_video_renderer_get_type (void); 310 | 311 | GstPlayerSignalDispatcher * 312 | gst_player_qt_signal_dispatcher_new (gpointer player); 313 | 314 | } 315 | 316 | #endif // QGSTPLAYER_H 317 | -------------------------------------------------------------------------------- /qt/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | fontawesome.js 5 | 6 | 7 | fontawesome-webfont.ttf 8 | 9 | 10 | -------------------------------------------------------------------------------- /qt/quickrenderer.cpp: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2015 Alexandre Moreno 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #include "quickrenderer.h" 22 | 23 | QuickRenderer::QuickRenderer(QObject *parent) 24 | : QObject(parent) 25 | , QGstPlayer::VideoRenderer() 26 | , sink() 27 | { 28 | 29 | } 30 | 31 | QuickRenderer::~QuickRenderer() 32 | { 33 | if (sink) gst_object_unref(sink); 34 | } 35 | 36 | GstElement *QuickRenderer::createVideoSink() 37 | { 38 | GstElement *qmlglsink = gst_element_factory_make("qmlglsink", NULL); 39 | 40 | GstElement *glsinkbin = gst_element_factory_make ("glsinkbin", NULL); 41 | 42 | Q_ASSERT(qmlglsink && glsinkbin); 43 | 44 | g_object_set (glsinkbin, "sink", qmlglsink, NULL); 45 | 46 | sink = static_cast(gst_object_ref_sink(qmlglsink)); 47 | 48 | return glsinkbin; 49 | } 50 | 51 | void QuickRenderer::setVideoItem(QQuickItem *item) 52 | { 53 | Q_ASSERT(item); 54 | 55 | g_object_set(sink, "widget", item, NULL); 56 | } 57 | -------------------------------------------------------------------------------- /qt/quickrenderer.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2015 Alexandre Moreno 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef QUICKPLAYER_H 22 | #define QUICKPLAYER_H 23 | 24 | #include 25 | #include 26 | #include "qgstplayer.h" 27 | 28 | class QuickRenderer : public QObject, public QGstPlayer::VideoRenderer 29 | { 30 | Q_OBJECT 31 | public: 32 | QuickRenderer(QObject *parent = 0); 33 | ~QuickRenderer(); 34 | 35 | GstElement *createVideoSink(); 36 | void setVideoItem(QQuickItem *item); 37 | 38 | private: 39 | GstElement *sink; 40 | }; 41 | 42 | #endif // QUICKPLAYER_H 43 | -------------------------------------------------------------------------------- /win32/gst-play/gst-play.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {C2483DBB-5396-4E7C-9015-6DFF40977D9A} 15 | gst-play 16 | 17 | 18 | 19 | Application 20 | true 21 | v120 22 | MultiByte 23 | 24 | 25 | Application 26 | false 27 | v120 28 | true 29 | MultiByte 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 | Level3 65 | Disabled 66 | true 67 | ..\..\lib;%(AdditionalIncludeDirectories) 68 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 69 | 70 | 71 | true 72 | %(AdditionalDependencies) 73 | 74 | 75 | 76 | 77 | Level3 78 | MaxSpeed 79 | true 80 | true 81 | true 82 | 83 | 84 | true 85 | true 86 | true 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /win32/gst-play/gst-play.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {fc1b7771-c924-430e-972e-87ef039fed70} 6 | 7 | 8 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 9 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 10 | 11 | 12 | 13 | 14 | source 15 | 16 | 17 | source 18 | 19 | 20 | 21 | 22 | source 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /win32/gst-player.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gst-play", "gst-play\gst-play.vcxproj", "{C2483DBB-5396-4E7C-9015-6DFF40977D9A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {C2483DBB-5396-4E7C-9015-6DFF40977D9A}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {C2483DBB-5396-4E7C-9015-6DFF40977D9A}.Debug|Win32.Build.0 = Debug|Win32 16 | {C2483DBB-5396-4E7C-9015-6DFF40977D9A}.Release|Win32.ActiveCfg = Release|Win32 17 | {C2483DBB-5396-4E7C-9015-6DFF40977D9A}.Release|Win32.Build.0 = Release|Win32 18 | {50C02A39-7349-4A6A-A2FD-B231C04FD485}.Debug|Win32.ActiveCfg = Debug|Win32 19 | {50C02A39-7349-4A6A-A2FD-B231C04FD485}.Debug|Win32.Build.0 = Debug|Win32 20 | {50C02A39-7349-4A6A-A2FD-B231C04FD485}.Release|Win32.ActiveCfg = Release|Win32 21 | {50C02A39-7349-4A6A-A2FD-B231C04FD485}.Release|Win32.Build.0 = Release|Win32 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | --------------------------------------------------------------------------------