Friday, May 15, 2020

Using swift to run blackmagic camera SDK in iOS Part2

This post is a continuation of the previous one, this time using the previously modified SDK and implementing the modifications to work on iOS.

Chapter 3: Edit the blackmagic SDK for  iOS
  1. Create a new project for iOS.
  2. Add only the last modified API of blackmagic SDK to the project file.
  3. Make the necessary modifications to make it work in iOS

Create a new project for iOS 


Add the Apple folder shown below to the project in the last edited blackmagic SDK.


To add them, check "Copy itmes if needed" and "Create groups" as indicated by the red arrow above
Edit the API file in the Apple folder for iOS.

Next time, RUN, there are five errors.( or some time six error)



Enter import UIKit In the following files


  • Utility/StringFunctions.swift 
  • Camera/PeripheralInterface.swift 
Then the error is reduced to tow.

Quit XCODE once you have reached this point.
And again, open the project for editing.
And that leaves six errors.

Then press the Fix button to fix the 'NSFontAttributeName' has been renamed to 'NSAttributedString.Key.font' error that remains in "StringFunctions.swift "


Next time you run with 5 errors, the error will disappear and the build will complete.


Chapter 4: Create an app to connect your IPhone to blackmagic pocket cinema camera

The procedure is as follows


  1. Creating the UI
  2. Bluetooth related implementations
  3. Edit info.plist for app permissions

Select "Main.storyboard" and place it in order of 1) Button 2) Table View 3) Table Cell. The table cells should be arranged so that they fit inside the table view.


Connecting Table Views and Buttons to ViewController

Select Inspectors from the View menu and select "Show Attributes Inspector.

Select the table view cell and edit the identifier to the cell

After editing, it looks like this

Next is the first part of editing ViewController.
In the following conditions, the error of the Tableview occurs, but it is not fixed yet.

import UIKit
import CoreBluetooth

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, InitialConnectionToUIDelegate,IncomingRecordControlToUIDelegate {

@IBOutlet var cameralist: UITableView!

weak var m_initialConnectionInterfaceDelegate: InitialConnectionFromUIDelegate?
weak var m_outgoingRecordControlDelegate: OutgoingRecordControlFromUIDelegate?
var m_displayedCameras = [DiscoveredPeripheral]()
var m_selectedCameraIdentifier: UUID?


override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.

cameralist.delegate = self
cameralist.dataSource = self

}
The red text is the part I added.
The parameter initialization in the middle is quoted from the following blackmagic SDK SelectViewController.swift



Here is the code for the bluetooth related initialization and finding the camera part It's almost the same here from the Blackmagic SDK SelectViewController.swift
override func viewWillAppear(_ animated: Bool) {

// Register as a InitialConnectionToUIDelegate with the CameraControlInterface,
// and assign CameraControlInterface as our InitialConnectionFromUIDelegate.
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let cameraControlInterface: CameraControlInterface = appDelegate.cameraControlInterface
cameraControlInterface.m_initialConnectionToUIDelegate = self
cameraControlInterface.m_recordControlToUIDelegate = self
m_initialConnectionInterfaceDelegate = cameraControlInterface
m_outgoingRecordControlDelegate = cameraControlInterface

// Disconnect any current connections, and start scanning for Bluetooth peripherals.
m_initialConnectionInterfaceDelegate?.disconnect()
m_initialConnectionInterfaceDelegate?.refreshScan()

// Clear cached cameras
m_displayedCameras.removeAll()
}

To fix the error displayed in cameraControlInterface, add a AppDelegate.swift as follows
import UIKit
import CoreBluetooth

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    let cameraControlInterface = CameraControlInterface()
The red text is the part I added.
If you run Clean Build Folder after editing the above, the ViewController.swift "Value of type 'AppDelegate' has no member 'cameraControlInterface'error" will be resolved.

Next, we'll add the update part of the peripheral information in Bluetooth. Here's another quote from SelectViewController.swift


func updateDiscoveredPeripheralList(_ discoveredPeripheralList: [DiscoveredPeripheral]) {
        // Remove all cached cameras.
        m_displayedCameras.removeAll()

        // Add all cameras from the updated discoveredPeripheralList.
        for peripheral in discoveredPeripheralList {
            m_displayedCameras.append(peripheral)
        }

        // Update UI to display our discovered cameras.
        cameralist.reloadData()
    }

Then add the following code to get the number of rows of tableview to display the list of cameras found in bluetooth and to specify the relationship with the display cell of tableview

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return m_displayedCameras.count
    }

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel!.text = m_displayedCameras[indexPath.row].name
     return cell
    }

Adding the above code will also resolve the ViewController error 'ViewController 'does not conform to protocol 'UITableViewDataSource'

Then, open the source code of info.plist add the key of the NSBroutothAlwaysUsageDescription as follows, and write the appropriate reason in <strings>



        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationPortraitUpsideDown</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>NSBluetoothAlwaysUsageDescription</key>
    <string>for camera control</string>
</dict>
</plist>

If there are no errors left after all the above code edits, it can be executed. Connect the real iPhone and run the test.

Select OK because the following dialog is displayed when the code is correctly transferred to the actual device.


Next, turn on the power of Blackmagic Pocket cinema camera and check if Bluetooth is turned on from Setup menu.
After that, if the iPhone app is running correctly, the name of the camera will be displayed on the screen as follows

Here is the code for the button to pair with the camera

@IBAction func connect(_ sender: Any) {
        let selectedIndex = 0
            if selectedIndex >= 0 {
                let uuid: UUID = m_displayedCameras[selectedIndex].peripheral.getPeripheralIdentifier()
                m_initialConnectionInterfaceDelegate?.attemptConnection(to: uuid)
            }

    }

Add the following red font code for the button code you connected in the beginning. This time, the code assumes that there is only one camera. If you have more than one camera and need to select one of them, you need to modify the second line, let selectedIndex = 0

After adding the code to connect the camera, build and run the app, make sure the camera's Bluetooth is turned on as before, make sure the camera name is displayed on the Iphone, and press the button on the iPhone.

When the pairing process has started properly, the camera will display the pair number below, and the pairing dialog will pop up on your IPhone.


If you enter the number displayed on the camera with your iPhone, pairing will be performed, and the following message will appear on the camera to show that the pairing was done correctly.


Finally, add a button for recording in the UI Builder, connect to the ViewController, and add the following code.

@IBAction func recStartstop(_ sender: Any) {
         m_outgoingRecordControlDelegate?.onRecordPressed()
    }

Once the app is running correctly and pairing with the camera has been performed, pressing the added button will alternate between Start/Stop recording.

The entire code is described below. Note that the code is only for normal systems, so abnormal system processing is not included.

ViewController.swift
import UIKit
import CoreBluetooth

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, InitialConnectionToUIDelegate, IncomingRecordControlToUIDelegate {

    @IBOutlet var cameralist: UITableView!

    weak var m_initialConnectionInterfaceDelegate: InitialConnectionFromUIDelegate?
    weak var m_outgoingRecordControlDelegate: OutgoingRecordControlFromUIDelegate?
    var m_displayedCameras = [DiscoveredPeripheral]()
    var m_selectedCameraIdentifier: UUID?

    override func viewDidLoad() {

        super.viewDidLoad()
        // Do any additional setup after loading the view.
        cameralist.delegate = self
        cameralist.dataSource = self
    }

    override func viewWillAppear(_ animated: Bool) {

        // Register as a InitialConnectionToUIDelegate with the CameraControlInterface,
        // and assign CameraControlInterface as our InitialConnectionFromUIDelegate.

        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let cameraControlInterface: CameraControlInterface = appDelegate.cameraControlInterface

        cameraControlInterface.m_initialConnectionToUIDelegate = self
        cameraControlInterface.m_recordControlToUIDelegate = self

        m_initialConnectionInterfaceDelegate = cameraControlInterface
        m_outgoingRecordControlDelegate = cameraControlInterface

        // Disconnect any current connections, and start scanning for Bluetooth peripherals.
        m_initialConnectionInterfaceDelegate?.disconnect()
        m_initialConnectionInterfaceDelegate?.refreshScan()

        // Clear cached cameras
        m_displayedCameras.removeAll()

    }

    func updateDiscoveredPeripheralList(_ discoveredPeripheralList: [DiscoveredPeripheral]) {

        // Remove all cached cameras.
        m_displayedCameras.removeAll()

        // Add all cameras from the updated discoveredPeripheralList.
        for peripheral in discoveredPeripheralList {
            m_displayedCameras.append(peripheral)
        }

        // Update UI to display our discovered cameras.
        cameralist.reloadData()

    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return m_displayedCameras.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel!.text = m_displayedCameras[indexPath.row].name
        return cell
    }

    @IBAction func connect(_ sender: Any) {
        let selectedIndex = 0
        if selectedIndex >= 0 {
            let uuid: UUID = m_displayedCameras[selectedIndex].peripheral.getPeripheralIdentifier()
            m_initialConnectionInterfaceDelegate?.attemptConnection(to: uuid)
        }
    }

    @IBAction func recStartstop(_ sender: Any) {
        m_outgoingRecordControlDelegate?.onRecordPressed()
    }
}

AppDelegate.swift
import UIKit
import CoreBluetooth

@UIApplicationMain

class AppDelegate: UIResponder, UIApplicationDelegate {

    let cameraControlInterface = CameraControlInterface()

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        return true
    }

    // MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
    }
}

Don't forget to add and edit the APIs provided by Blackmagic, as well as the Info.plist I wrote at the beginning!

No comments:

Post a Comment