Skip to content

Instantly share code, notes, and snippets.

@nkallen
Created January 30, 2017 16:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nkallen/6e3f5cf4e174a9d4f9d915fa9ca7a1a3 to your computer and use it in GitHub Desktop.
Save nkallen/6e3f5cf4e174a9d4f9d915fa9ca7a1a3 to your computer and use it in GitHub Desktop.
#ifndef pipeline_h
#define pipeline_h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, State) {
playing,
paused,
null,
ready,
};
@interface Context : NSObject
- (void)pushThreadDefault;
- (void)popThreadDefault;
@end
@interface Source : NSObject
- (void)setCallbackAsync;
- (void)attach:(Context *)context;
@end
@interface XObject : NSObject // FIXME
- (void)set:(NSString *)name to:(id)value;
@end
@interface Main: NSObject
- (id)initWithContext:(Context *)context;
- (void)run;
@end
// MARK: GStreamer
@interface Element : XObject
@property (readwrite) NSString *name;
- (BOOL)linkTo:(Element *)other; // FIXME error handling
- (BOOL)setState:(State)state; // FIXME error handling
@end
@interface StateChangeMessage: NSObject
@property (readonly) State oldState;
@property (readonly) State newState;
@property (readonly) State pendingState;
@end
@interface ErrorMessage: NSObject
@property (nonnull, readonly) NSError *error;
@property (nonnull, readonly) NSString *debugInfo;
@end
@interface Message : NSObject
@property (nonnull, readonly) Element *source;
- (nullable StateChangeMessage *)parseStateChanged;
- (nullable ErrorMessage *)parseError;
@end
@interface Bus : XObject
- (Source *)createWatch;
- (void)onMessage:(NSString *)name callback:(void (^)(Bus *bus, Message *message))callbackBlock;
@end
@interface Pipeline : Element
@property (readonly) Bus *bus;
- (void)add:(Element *)element;
- (nullable Element *)getByInterface;
@end
@interface ElementFactory : NSObject
+ (nullable Element *)make:(NSString *)name;
@end
@interface VideoOverlay: Element
- (void)setWindowHandle:(UIView *)windowHandle;
@end
@interface GStreamer: NSObject
+ (nullable Pipeline *)parseLaunch:(NSString *)command error:(NSError **)error;
@end
NS_ASSUME_NONNULL_END
#endif /* pipeline_h */
import UIKit
protocol GStreamerDelegate {
func onError()
func onStateChange()
func onInitialized()
}
class GStreamerService {
let delegate: GStreamerDelegate
let videoView: UIView
var pipeline: Pipeline!
init(delegate: GStreamerDelegate, videoView: UIView) {
self.delegate = delegate
self.videoView = videoView
}
func play() {
pipeline.setState(.playing)
}
func pause() {
pipeline.setState(.paused)
}
private func onError() {
delegate.onError()
pipeline.setState(.null)
}
private func onStateChange(message: Message) {
if message.source == pipeline {
delegate.onStateChange()
}
}
func run() {
DispatchQueue.global().async {
let context = Context()
context.pushThreadDefault()
do {
try self.pipeline = GStreamer.parseLaunch("avfvideosrc device-index=1 ! video/x-raw,width=352,height=288 ! tee name=t t. ! queue ! autovideosink t. ! queue ! vtenc_h264 bitrate=800 max-keyframe-interval-duration=2000000000 max-keyframe-interval=60 allow-frame-reordering=false realtime=true quality=0.5 ! flvmux streamable=1 ! rtmpsink location='rtmp://ec2-54-152-176-149.compute-1.amazonaws.com:1935/live/iphone live=1'")
self.pipeline.setState(.ready)
let videoSink = self.pipeline.getByInterface()!
(videoSink as! VideoOverlay).setWindowHandle(self.videoView)
let bus = self.pipeline.bus
let source = bus.createWatch()
source.setCallbackAsync()
source.attach(context)
bus.onMessage("error") { (bus, message) in
print("error", message.parseError()!)
self.pipeline.setState(.null)
}
bus.onMessage("state-changed") { (bus, message) in
if message.source == self.pipeline {
print(message.source.name, message.parseStateChanged()!)
}
}
let mainLoop = Main(context: context)
self.delegate.onInitialized()
mainLoop.run()
context.popThreadDefault()
} catch let error {
print("error", error)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment