How to create RTMP/RTSP player using FFMpeg for ios - ios

I am working on an app using RTMP/RTSP links to broadcast/play live audio/video.As iOS devices support HTTP , but my requirement is to play RTMP/RTSP Links.
I want to create my custom player using FFMpeg framework.I have searched over internet , ried many solutions but did not find any solution.

there's a Xcode project based on ffmpeg. It's possible to play RTSP links. Have a look at it:
https://github.com/durfu/DFURTSPPlayer
If you want to know more about RTSP, I can highly recommend you the following link:
https://www.rfc-editor.org/rfc/rfc2326

Here is an overview of current solutions for rtsp on iOS:
https://gist.github.com/oc2pcoj/e55795550984d205d109
I use ijkplayer at current project for playing video stream from IP-cam. It works fine.

To play an rtsp stream on iOS using ffmpeg I recommend https://github.com/teocci/RTSP-Client-iOS
For reference, here is an Objective-C interface to RTSP-Client-iOS/FFMpegDecoder/RTSPPlayer.m based on RTSP-Client-iOS/RtspClient/ViewController.swift;
//
// ViewController.h
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIImageView *imageViewInstance1;
#end
//
// ViewController.m
//
#import "ViewController.h"
#import "RTSPPlayer.h"
RTSPPlayer *rtspPlayer;
int frameIndex;
NSTimer *timerRefresh;
#define CAMERA_RTSP_ADDRESS "rtsp://..."
#define CAMERA_FPS (30.0)
#define TIMER_INTERVAL_SECONDS (1.0/CAMERA_FPS)
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString* address = #CAMERA_RTSP_ADDRESS;
rtspPlayer = [[RTSPPlayer alloc] initWithVideo:address usesTcp:false];
rtspPlayer.outputWidth = 640;
rtspPlayer.outputHeight = 480;
[rtspPlayer seekTime:0.0];
timerRefresh = [NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL_SECONDS target:self selector:#selector(run:) userInfo:nil repeats:YES];
}
-(void) run:(NSTimer *) timer
{
if(![rtspPlayer stepFrame])
{
[timerRefresh invalidate];
[rtspPlayer closeAudio];
}
UIImage* uiImage = rtspPlayer.currentImage;
_imageViewInstance1.image = uiImage;
frameIndex++;
}
#end
To create an ImageView object in the user interface (_imageViewInstance1);
Project Navigator (left pane) - [INSERTAPPLICATIONNAME]
Open Main.storyboard
Select View Controller Scene - View Controller - View
Select the Library button (top right: circle with inside square)
Search for 'Image View'
Drag and drop a new View Image Object into View Controller Scene - View Controller - View (adjacent 'Safe Area')
Create an outlet connection for the new Image View object
Select the Assistant Editor button (top right: two intersecting circles)
Select file ViewController.h in the Project Navigator
If necessary hide the left and right panes to create more space (top right: blue box with left vertical bar, blue box with right vertical bar)
hold the Ctrl key and drag the new image view object to the ViewController.h file (immediately below #interface ViewController: UIViewController) - name the object reference as imageViewInstance1

Related

ObjectiveC - [self.view viewWithTag] returning null

I am completely stumped and have been researching for days. Probably something really simple that I am missing.
I have a ViewController which contains a custom UIView called GameView, and a UIView called buttonBox which contains a "next level" button. What I am trying to achieve is when the level is completed in GameView, it fires a function in my ViewController which shows the buttonBox so the user can click the "next level" button. It simply will not work.
I have attempted this in 3 ways, neither have worked:
Creating an IBOutlet in the ViewController, connecting it to the hidden UIView (and it was definitely connected) and calling setHidden:NO.
Calling the [self.view viewWithTag:xxx] and then calling setHidden:NO.
Using hidden=NO instead of setHidden:NO.
Relevant code for ViewController as follows:
#interface PlayViewController : UIViewController
#property GameView *gv;
#property (strong, nonatomic) IBOutlet UIView *buttonBox;
-(void) showButtonBox;
#end
#implementation PlayViewController
#synthesize buttonBox;
...
- (IBAction)showButtonBox {
UIView *uiv = (UIView*) [self.view viewWithTag:999];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Showing box function");
NSLog(#"%#", uiv);
uiv.hidden = NO;
});
}
#end
And my custom view:
#implementation GameView
...
dispatch_async(bgQueue, ^{
_loopRunning = true;
//NSLog(#"Calling main loop...");
while ([self loopRunning])
{
...
PlayViewController * pvc = [[PlayViewController alloc]init];
[pvc showButtonBox];
...
}
#end
The thing is, the variable uiv is returning null in NSLog, which is obviously why hidden is not working, but I have no idea why. It also didn't work when I was using IBOutlet.
Also, current output from NSLog is as follows:
2015-11-24 00:18:38.612 ib[12579:1264539] Showing box function
2015-11-24 00:18:38.612 ib[12579:1264539] (null)
Thanks in advance.
Correct Answer:
The problem was that I was using StoryBuilder to build my UI, but by using the alloc init method was creating a new view controller (which is never shown) instead of correctly referencing the view controller which was being displayed. This is achieved by passing the view controller being displayed to the view in the viewDidLoad function, see below:
#implementation PlayViewController
#synthesize buttonBox;
#synthesize gv;
- (void)viewDidLoad
{
[super viewDidLoad];
gv = [self.view viewWithTag:777];
[gv setPlayViewController:self];
}
...
Man, it's simple. Let's take a look at:
#implementation GameView
...
dispatch_async(bgQueue, ^{
_loopRunning = true;
//NSLog(#"Calling main loop...");
while ([self loopRunning])
{
...
PlayViewController * pvc = [[PlayViewController alloc]init];
[pvc showButtonBox];
...
}
#end
Here we have the issue:
dispatch_async(bgQueue, ^{
I assume, bgQueue stands for "background queue", which means this is not served by the main thread (the UI thread).
Having that said, it's quite naive to expect
[pvc showButtonBox];
to work properly. Just move this code into the main thread. For instance, you can just wrap the aforementioned line of code into a dispatch_async on the main queue. That should solve your probem, if your outlets and/or tags are OK. Cheers.
[[PlayViewController alloc]init];
This creates a new instance of PlayViewController. Where have you defined your outlets and views?
In a storyboard? You can't use this initialiser - nothing from the storyboard will be picked up, you have to use a segue or initializeViewControllerWithIdentifier:.
In a xib file? Is it called PlayViewController.xib? If not, it won't be picked up by the initialiser. Plain alloc/init of a view controller will only find a nib file as described in the documentation of the nibName property.
Do you really want alloc / init at all? Do you actually want to make a new view controller, or is one already on the screen?
From your comments it seems option 3 is the right answer. The PlayViewController is already on the screen, alloc/init is creating a new instance of it, which is never being put on screen, which never loads any views regardless of storyboards or nibs.
You need to get a reference to the existing instance of PlayViewController. Without knowing the structure of your app it's not too easy to say how that's done - is it presenting the game view? Is the game view a subview of the view controller's view? You may need to pass in a reference (weak) to the game view when it is created, at viewDidLoad, or set up an outlet in the storyboard.

Add webMap as layer with ArcGIS mapView for iOS app project

I'm trying to code in a basic ArcGIS workflow into my iOS project. I am new to this platform and can use some pointers. My workflow is as follows.
1.) Create mapView displaying satellite (world style) map.
2.) Add a public webMap from my user account on ArcGIS Online as an overlay/layer on the satellite map.
What I've tried
//.h
#import <ArcGIS/ArcGIS.h>
#interface ViewController : UIViewController <AGSWebMapDelegate>
#property (strong, nonatomic) IBOutlet AGSMapView *mapView;
//.m
// Add basemap
NSURL* url = [NSURL URLWithString:#"http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"];
AGSTiledMapServiceLayer *tiledLayer = [AGSTiledMapServiceLayer tiledMapServiceLayerWithURL:url];
[self.mapView addMapLayer:tiledLayer withName:#"Basemap Tiled Layer"];
//If I run this part alone, I'll get the satellite map.
AGSWebMap* webmap = [[AGSWebMap alloc] initWithItemId:#"bb9b8c172e8142f995526bf658078f54" credential:nil];
webmap.delegate = self;
[webmap openIntoMapView:self.mapView];
//When I add this webMap code and run the project, I get a blank white screen.
//.m cont.
- (void)mapViewDidLoad:(AGSMapView *) mapView {
NSLog(#"mapView didLoad");
}
- (void) webMapDidLoad:(AGSWebMap*) webMap {
NSLog(#"webmap added successfully");
}
//Neither of these logs get called.
Questions.
1.) Is it right to use AGSTiledMapServiceLayer as my basemap? Also, is it right to use AGSWebMap for my ArcGIS Online map?
2.) My goal is to be able to add and remove multiple layers to and from a satellite basemap, one at a time. Am I on the right track?
I'm currently using MapBox to achieve this but I'm starting to experiment with ArcGIS SDK and it's features.
Thanks in advance.
You are almost there. Make sure all 3 of these items are in the proper pace.
From the discussion from https://developers.arcgis.com/ios/objective-c/guide/viewing-web-map.htm.
Make these calls where you made them before (presumably viewDidLoad)
instantiate an AGSWebMap object // 1
An instance of your class must then be set as the web map's delegate // 2
// 1
AGSWebMap* webmap = [[AGSWebMap alloc] initWithItemId:#"bb9b8c172e8142f995526bf658078f54" credential:nil];
// 2
webmap.delegate = self;
Then update the handler webMapDidLoad() // 3
// open the web map into a map view in the delegate handler
- (void) webMapDidLoad:(AGSWebMap*) webMap {
// 3
[webmap openIntoMapView:self.mapView];
NSLog(#"webmap added successfully");
}

Xcode, create two the same MyMoviePlayerController in two ViewController

I have a ViewController:
ReadViewController.h
ReadViewController.m
And I have a MPMoviePlayerController inside ReadViewController:
ReadViewController.h
#interface ReadViewController : UIViewController
#property (nonatomic, strong) MyMoviePlayerController *myPlayView;
#end
ReadViewController.m
- (void)viewDidLoad
{
.....
.....
.....
[self.view addSubview:self.myPlayView.view];
}
I created two objects of ReadViewController which one is small size used for “preview” and another is Screen Size.
I put the two ViewControllers in two place:
ReadViewController *bigSizeReadViewController = [[ReadViewController alloc] init];
//put bigSizeReadViewController inside an UITabBarController
.....
ReadViewController *smallSizeReadViewController = [[ReadViewController alloc] init];
smallSizeReadViewController.view.frame = CGRectMake(200, 300, 400, 600);
[...... addSubView:smallSizeReadViewController.view];
I put the two ViewControllers in two place.
When I run this on IPAD Simulator, self.myPlayView inside small size's ReadViewController can be played normally.
But self.myPlayView inside big size's ReadViewController can not be played normally and show black screen.
Could anyone help me with this issue?
Sorry for my bad English.
You have to initialize and setup each of the myPlayView properties separately, and start playing them each individually.
There will be no guarantees that they will be synchronized as they are independent AVPLayer objects. You;ll have to write the extra code to keep them in sync.

Second UITabBar

I already looking since a hour for a solution of my problem.
A picture can tell more then thousand words:
I have two TabBars in my ViewController. The first one I created with the storyboard, and it works. Now I would like to have the second one to select the type of connection. Because every connection type has some own things to fill. I just drag and drop a new UITabTab into my ViewController, added a third TabBar item but I don't know what is next. How to handle the second TabBar. What methods do I need? How to catch touches on this items, so I can change a view?
You're using a UITabBarViewController or a UIViewController? I suspect the first is the case and you don't know how to hook up two of the same to one ViewController. What you need to do is to take apart the delegate methods for the UITabBar so you can do it twice in the same controller.
You should do the following:
Use a regular UIViewController
Drag two UITabBars onto the View
Connect them to your ViewController
Create two implementations of the UITabBarDelegate for each UITabBar in separate classes
At viewDidLoad or a similar event create instances of those classes and set the "delegate" of each UITabBar to that instance
Some example code
First create a new class for the bar on top. It only needs to do one thing:
#import "LVDTopTabDelegate.h"
#implementation LVDTopTabDelegate
// This is the only required part of the delegate
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item;
{
// Handle what you wanted to do
}
#end
The second one is more or less the same
#import "LVDBottomTabDelegate.h"
#implementation LVDBottomTabDelegate
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item;
{
// Handle what you wanted to do
}
#end
You viewDidLoad should look approximately like this:
#implementation LVDViewController
- (void)viewDidLoad;
{
LVDTopTabDelegate *topTabDelegate = [[LVDTopTabDelegate alloc] init];
self.topTabBar.delegate = topTabDelegate; // self.topTabBar is an IBOutlet for your tab bar
LVDBottomTabDelegate *topTabDelegate = [[LVDBottomTabDelegate alloc] init];
self.bottomTabBar.delegate = bottomTabDelegate;
}
#end

passing parameter to view in IOS after a button is pressed

I am new to IOS programming. So far I have been programming in android. So in android when pressing a button code for passing an argument would be like that:
Intent i = new Intent(MainScreen.this,OtherScreen.class);
Bundle b = new Bundle();
b.putString("data_1",data);
i.putExtras(b);
startActivity(i);
and on the activity that opens, i would write something like this:
Bundle b = getIntent().getExtras();
ski_center=b.getString("data_1");
what methods should I need to change in MainScreen and in OtherScreen in IOS to achieve the above.
Basically I will have 3 buttons lets say in my MainScreen and each of it will open the Otherview but each time a different parameter will be passed.
Foe example for each button i have code like these in MainScreen.m
#synthesize fl;
-(IBAction) ifl:(id) sender {
}
So I need your help in where to place the "missing" code, too.
Declare an iVar for your UIViewController ( Android's Activity) like a property in Java.
In MainViewController.m
OtherUIViewController * contr = [[OtherUIViewController alloc] initWithNibname...];
contr.data = yourData;
Edited: added full code...
Intent i = new Intent(MainScreen.this,OtherScreen.class);
Bundle b = new Bundle();
b.putString("data_1",data);
here the MainScreen is the calling code, now in iOS it will be the MainUIViewcontroller
create a OtherUIViewController like this:
OtherUIViewController.h
#interface OtherUIViewController : UIViewController
{
NSData* data;
}
#property (strong, nonatomic) NSData* data;
in the OtherUIViewController.m
#implementation OtherUIViewController.m
#synthetize data;
// override
- (void)viewDidLoad
{
[super viewDidLoad];
// do something with data here
}
to have the 3 different behaviors, the data can be an int, or an NSString.
And in the - (void)viewDidLoad you will check the data value and do 3 diff things.
I hope it helps

Resources