1

Currently, I am converting the hardware decoding Obj-C code to Swift version. (Xcode 8, Swift 3).

I don't know how to set up a dictionary to set up an output option on the screen, also, I don't know how to use it.

The following code works fine in Obj-C project:

// set some values of the sample buffer's attachments
CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, YES);
CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);

I tried the following Swift code, but there was a runtime error:

// i got run-time error
let attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer!, true)
let dict = unsafeBitCast(attachments, to: CFMutableDictionary.self)
CFDictionarySetValue(dict, unsafeBitCast(kCMSampleAttachmentKey_DisplayImmediately, to: UnsafeRawPointer.self), unsafeBitCast(kCFBooleanTrue, to: UnsafeRawPointer.self))

Is it wrong to convert the CFString to UnsafeRawPointer? or Is it wrong to use the CFDictionarySetValue method?

this is my error log.

2016-11-24 16:50:44.458 MyApp[35288:3519253] -[__NSSingleObjectArrayI __setObject:forKey:]: unrecognized selector sent to instance 0x6000002045a0
2016-11-24 16:50:44.466 MyApp[35288:3519253] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSingleObjectArrayI __setObject:forKey:]: unrecognized selector sent to instance 0x6000002045a0'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010b02734b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x000000010a0e421e objc_exception_throw + 48
    2   CoreFoundation                      0x000000010b096f34 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
    3   CoreFoundation                      0x000000010afacc15 ___forwarding___ + 1013
    4   CoreFoundation                      0x000000010afac798 _CF_forwarding_prep_0 + 120
    5   MyApp                             0x000000010937ac7a _TFC14MyApp16ViewerController21receivedRawVideoFramefT5frameGSaVs5UInt8_4withVs5Int32_T_ + 4890
    6   MyApp                             0x000000010937d8e2 _TFC14MyApp16ViewerController12MainCallBackfTVs5Int3212callbackCodeS1_8argumentGSqSv_7argSizeS1__T_ + 4242
    7   MyApp                             0x000000010937daed _TToFC14MyApp16ViewerController12MainCallBackfTVs5Int3212callbackCodeS1_8argumentGSqSv_7argSizeS1__T_ + 61
    8   MyApp                            0x000000010937dd56 _TTDFC14MyApp16ViewerController12MainCallBackfTVs5Int3212callbackCodeS1_8argumentGSqSv_7argSizeS1__T_ + 70
    9   MyApp                             0x000000010937dcfe _TTWC14MyApp16ViewerControllerS_18IJCallbackProtocolS_FS1_12MainCallBackfTVs5Int3212callbackCodeS2_8argumentGSqSv_7argSizeS2__T_ + 62
    10  MyApp                             0x00000001093b22b2 _TFC14MyApp11AppDelegate19MainCallBack_StreamfTVs5Int32S1_GSqSv_S1__T_ + 258
    11  MyApp                             0x00000001093d26d3 _TFZFC14MyApp19IJStreamCoreWrapper6AttachFTSv2ipSS4portSi_T_U_FTVs5Int32S1_GSqSv_S1_GSqSv__T_ + 355
    12  MyApp                             0x00000001093d2719 _TToFZFC14MyApp19IJStreamCoreWrapper6AttachFTSv2ipSS4portSi_T_U_FTVs5Int32S1_GSqSv_S1_GSqSv__T_ + 9
    13  MyApp                             0x00000001093ee176 _ZL8CallbackPN14CStreamManager9Session_TEiPvi + 70
    14  MyApp                             0x00000001093f09d3 _Z25StreamManagerThread_VideoPv + 3155
    15  libsystem_pthread.dylib             0x000000010e494aab _pthread_body + 180
    16  libsystem_pthread.dylib             0x000000010e4949f7 _pthread_body + 0
    17  libsystem_pthread.dylib             0x000000010e494221 thread_start + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException
jtbandes
  • 115,675
  • 35
  • 233
  • 266
  • Displaying what's the run-time error log might be helpful. – Ahmad F Nov 24 '16 at 07:39
  • I'm not sure about the exact syntax, but if I remember correctly `CFDictionary` should be bridged to `NSDictionary`... There must be a simple solution involving the swift keyword `as`. – Nicolas Miari Nov 24 '16 at 07:56
  • 1
    it's also bridged to Swift's native `Dictionary`. Use that. – Alexander Nov 24 '16 at 07:59
  • Nicolas Miami I've already used the ' as ' keyword. But, Similarly, there is an error. Do you mean this? : CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately as! UnsafeMutablePointer, kCFBooleanTrue as! UnsafeMutablePointer) – Byeongju Park Nov 24 '16 at 08:02
  • Ahmad F thanks. i attached error log – Byeongju Park Nov 24 '16 at 08:04
  • Alexander Momchliov Thank you for your comment. but How can i use it? – Byeongju Park Nov 24 '16 at 08:04
  • CoreFoundation types `CFArray`, `CFArrayRef`, `CFDictionary`, `CFDictionaryRef`, etc. and Foundation types `NSArray`, `NSMutableArray`, etc. can all be bridged to Swift types with `as`. I strongly advise against using these types in Swift. Using the native types makes everything much much simpler. In my answer I give a little demonstration. – Alexander Nov 24 '16 at 08:10

3 Answers3

1

I was only able to get this working with the following:

let attachments = CMSampleBufferGetSampleAttachmentsArray(buf!, createIfNecessary: true)
let dict = unsafeBitCast(CFArrayGetValueAtIndex(attachments, 0), to: CFMutableDictionary.self)
CFDictionarySetValue(dict,
                     unsafeBitCast(kCMSampleAttachmentKey_DisplayImmediately, to: UnsafeRawPointer.self),
                     unsafeBitCast(kCFBooleanTrue, to: UnsafeRawPointer.self))

I tried @Alexander's suggestion, and although it compiles and executes, the underlying CFDictionary is not mutated and the desired result is not achieved.

//  let attachments = CMSampleBufferGetSampleAttachmentsArray(buf!, createIfNecessary: true) as! Array<Dictionary<String, Any>>
//  var dict = attachments[0]
//  dict[kCMSampleAttachmentKey_DisplayImmediately as String] = true
tmm1
  • 2,025
  • 1
  • 20
  • 35
0

In the first code snippet, you have a call to CFArrayGetValueAtIndex, which returns a dictionary that you pass to CFDictionarySetValue.

In the second code snippet, you don't call CFArrayGetValueAtIndex. You just pass the array to CFDictionarySetValue. Since an array is not a dictionary, you get a fatal error.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
0

When you convert code to Swift, it's much best to understand the semantic of the program, and rewrite Swift code that matches. Don't try to just convert the syntax bit by bit.

CMSampleBufferGetSampleAttachmentsArray returns you a reference to a CFArray of CFDictionary instances. Casting this CFArrayRef to CFMutableDictionaryRef has the effect of just making a reference to the first instance.

It's best to just use Swift's native types. I can't provide an exact implementation because I'm not to sure of the types in play, but here's a start

//TODO: give me a better name
let array = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer!, true) as [[String: Bool]] //TODO:

//TODO: give me a better name
var firstDict = array[0]

firstDict[kCMSampleAttachmentKey_DisplayImmediately as String] = true
Alexander
  • 59,041
  • 12
  • 98
  • 151