1

Note for the readers: I tag this question as "codenameone" and "objective-c" because it refers to the use of a native interface, which implementation is in Objective-C, inside a Java application. If you don't know what is a native interface, it's explained here: https://www.codenameone.com/how-do-i---access-native-device-functionality-invoke-native-interfaces.html - I don't know if my code doesn't work because it have issues in the Java part or in the Objective-C part


In my previous question "From video to image in Codename One", the answer was that "the only way to do that is through native code".

I tried to write a native interface (for iOS, at the moment) to do that, but the preview is not shown. I merged some code that I found on Stack Overflow, because I'm not an Objective-C programmer. It compiles without errors, I attach the code and the native log.

Could you help me to fix my code, please? Thank you

main class:

Form hi = new Form("Video editing test", BoxLayout.y());
        Button previewBtn = new Button("Extract preview of video");
        Label label = new Label("") {
            public Dimension calcPreferredSize() {
                Dimension dim = super.calcPreferredSize();
                dim.setHeight(CN.convertToPixels(50, false));
                return dim;
            }
        };
        hi.addAll(previewBtn, label);
        hi.show();

        previewBtn.addActionListener(l -> {
            CN.openGallery(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent ev) {
                    if (ev.getSource() != null) {
                        try {
                            Log.p("Source video (temp file): " + ev.getSource(), Log.DEBUG);
                            String extension = ((String) ev.getSource()).substring(((String) ev.getSource()).lastIndexOf('.') + 1);
                            String videoFile = getAppHomePath() + "myFunVideo" + "." + extension;
                            String jpegFile = getAppHomePath() + "myFunVideoPreview" + "." + "jpeg";
                            Util.copy(FileSystemStorage.getInstance().openInputStream((String) ev.getSource()), FileSystemStorage.getInstance().openOutputStream(videoFile));
                            Log.p("Video copied into app home path: " + videoFile, Log.DEBUG);
                            VideoEditing videoEditing = NativeLookup.create(VideoEditing.class);
                            if (videoEditing != null && videoEditing.isSupported()) {
                                videoEditing.getImageFromVideo(videoFile, jpegFile);
                                Log.p("Native code executed, the jpeg file is: " + jpegFile, Log.DEBUG);
                                EncodedImage encodedImg = EncodedImage.create(FileSystemStorage.getInstance().openInputStream(jpegFile));
                                label.getAllStyles().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FIT);
                                label.getAllStyles().setBgImage(encodedImg);
                                label.repaint();
                                Log.p("Preview image shown fitted inside a Label which height is 5 cm", Log.DEBUG);
                            } else {
                                Log.p("Native code cannot be executed!!!", Log.WARNING);
                                FontImage warning = FontImage.createMaterial(FontImage.MATERIAL_WARNING, "Label", 50);
                                label.getAllStyles().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FIT);
                                label.getAllStyles().setBgImage(warning);
                                label.repaint();
                            }
                        } catch (IOException ex) {
                            Log.e(ex);
                        }
                    }
                }
            }, CN.GALLERY_VIDEO);
        });

native interface:

public interface VideoEditing extends NativeInterface {

    /**
     * Extract the first frame from the given video file and saves it to the given jpeg file
     * @param videoFile FileSystemStorage path of the video file
     * @param jpegFile FileSystemStorage path of the jpeg image file, 
     */
    public void getImageFromVideo(String videoFile, String jpegFile);

}

native interface implementation:

#import "net_informaticalibera_videoediting_VideoEditingImpl.h"
#import <AVFoundation/AVAsset.h>
#import <AVFoundation/AVAssetImageGenerator.h>

@implementation net_informaticalibera_videoediting_VideoEditingImpl

-(void)getImageFromVideo:(NSString*)param param1:(NSString*)param1{
    NSLog(@"Called iOS native code, method \"getImageFromVideo\"");
    NSString* videoFile = param;
    NSString* jpegFile = param1;
    NSLog(@"The video file is: %@\nThe jpeg file is: %@", videoFile, jpegFile);

    NSURL* contentURL = [NSURL fileURLWithPath:videoFile];

    // https://stackoverflow.com/a/10677003
    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:contentURL options:nil];
    AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    generator.appliesPreferredTrackTransform = YES;
    NSError *err = NULL;
    CMTime time = CMTimeMake(1, 60);
    CGImageRef imgRef = [generator copyCGImageAtTime:time actualTime:NULL error:&err];

    UIImage *theImage = [[[UIImage alloc] initWithCGImage:imgRef] autorelease];
    // Save image.
    [UIImageJPEGRepresentation(theImage, 0.9) writeToFile:jpegFile atomically:YES];

    CGImageRelease(imgRef);
    [asset release];
    [generator release];
}

-(BOOL)isSupported{
    return YES;
}

@end

native log:

Sep 24 00:32:47 iPhone MyApplication(libAccessibility.dylib)[1545] <Notice>: Retrieving resting unlock: 0
Sep 24 00:32:47 iPhone MyApplication(FrontBoardServices)[1545] <Notice>: [FBSDisplaySource 1-1] silently connecting <FBSDisplayConfiguration: 0x281d6c380; Main; mode: "375x812@3x 60Hz p3 SDR">
Sep 24 00:32:47 iPhone MyApplication(FrontBoardServices)[1545] <Notice>: [FBSDisplaySource 1-1] initialized <FBSDisplayConfiguration: 0x281d6c380; Main; mode: "375x812@3x 60Hz p3 SDR">
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: Task <20C63C46-4F13-4D86-8115-28DA44623E13>.<0> {strength 1, tls 8, ct 0, sub 0, sig 0, ciphers 1, bundle 0, builtin 0}
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC Enabling TLS [1:0x2811436c0]
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC TCP Conn Start [1:0x2811436c0]
Sep 24 00:32:47 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: [C1 Hostname#82a7f361:443 tcp, url hash: fe9d5b61, tls] start
Sep 24 00:32:47 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: nw_connection_report_state_with_handler_locked [C1] reporting state preparing
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: Task <20C63C46-4F13-4D86-8115-28DA44623E13>.<0> setting up Connection 1
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: Sending CFNA PAC query
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: Received CFNA PAC response
Sep 24 00:32:47 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: nw_endpoint_flow_protocol_connected [C1.1 IPv4#ab6e0ca5:48083 in_progress channel-flow (satisfied)] Transport protocol connected
Sep 24 00:32:47 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: nw_endpoint_flow_protocol_connected [C1.1 IPv4#ab6e0ca5:48083 in_progress channel-flow (satisfied)] Output protocol connected
Sep 24 00:32:47 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: nw_connection_report_state_with_handler_locked [C1] reporting state ready
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC TCP Conn Connected [1:0x2811436c0]: Err(16)
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC TCP Conn Event [1:0x2811436c0]: 1
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC Enabling TLS [1:0x2811436c0]
Sep 24 00:32:47 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: nw_connection_report_state_with_handler_locked [C1] reporting state preparing
Sep 24 00:32:47 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: nw_endpoint_flow_protocol_connected [C1.1 IPv4#ab6e0ca5:48083 in_progress channel-flow (satisfied)] Transport protocol connected
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC TLS Event [1:0x2811436c0]: 1, Pending(0)
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC TLS Event [1:0x2811436c0]: 11, Pending(0)
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC TLS Event [1:0x2811436c0]: 14, Pending(0)
Sep 24 00:32:47 iPhone MyApplication(HangTracer)[1545] <Notice>: HTHangEventCreate: HangTracing is disabled. Not creating a new event.
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: System Trust Evaluation yielded status(0)
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC TLS Trust Result [1:0x2811436c0]: 0
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC TLS Event [1:0x2811436c0]: 2, Pending(0)
Sep 24 00:32:47 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: nw_endpoint_flow_protocol_connected [C1.1 IPv4#ab6e0ca5:48083 in_progress channel-flow (satisfied)] Output protocol connected
Sep 24 00:32:47 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: nw_connection_report_state_with_handler_locked [C1] reporting state ready
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC TLS Event [1:0x2811436c0]: 20, Pending(0)
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC TCP Conn Event [1:0x2811436c0]: 8
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC TLS Handshake Complete [1:0x2811436c0]
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: Task <20C63C46-4F13-4D86-8115-28DA44623E13>.<0> now using Connection 1
Sep 24 00:32:47 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: nw_endpoint_flow_protocol_connected [C1.1 IPv4#ab6e0ca5:48083 ready channel-flow (satisfied)] Output protocol connected
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: Task <20C63C46-4F13-4D86-8115-28DA44623E13>.<0> sent request, body N
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: Task <20C63C46-4F13-4D86-8115-28DA44623E13>.<0> received response, status 200 content K
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: Task <20C63C46-4F13-4D86-8115-28DA44623E13>.<0> response ended
Sep 24 00:32:47 iPhone MyApplication(CFNetwork)[1545] <Notice>: Task <20C63C46-4F13-4D86-8115-28DA44623E13>.<0> done using Connection 1
Sep 24 00:32:47 iPhone MyApplication(AccessibilityUtilities)[1545] <Notice>: Will reevaluate code items and load any needed ax code items now
Sep 24 00:32:47 iPhone MyApplication(AccessibilityUtilities)[1545] <Notice>: found 45 axbundle(s) requiring load
Sep 24 00:32:47 iPhone MyApplication(QuickLook)[1545] <Notice>: Loading PDFKit
Sep 24 00:32:47 iPhone MyApplication(AccessibilityUtilities)[1545] <Notice>: Finished loading ax code items
Sep 24 00:32:48 iPhone MyApplication(AccessibilityUtilities)[1545] <Notice>: Will reevaluate code items and load any needed ax code items now
Sep 24 00:32:48 iPhone MyApplication(AccessibilityUtilities)[1545] <Notice>: found 0 axbundle(s) requiring load
Sep 24 00:32:48 iPhone MyApplication(AccessibilityUtilities)[1545] <Notice>: Finished loading ax code items
Sep 24 00:33:15 iPhone MyApplication(AXRuntime)[1545] <Error>: Unknown client: MyApplication
Sep 24 00:33:15 iPhone MyApplication(AccessibilityUtilities)[1545] <Notice>: Will reevaluate code items and load any needed ax code items now
Sep 24 00:33:15 iPhone MyApplication(AccessibilityUtilities)[1545] <Notice>: found 1 axbundle(s) requiring load
Sep 24 00:33:15 iPhone MyApplication(AccessibilityUtilities)[1545] <Notice>: Finished loading ax code items
Sep 24 00:33:17 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC TCP Conn Cancel [1:0x2811436c0]
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: [C1 Hostname#82a7f361:443 tcp, url hash: fe9d5b61, tls] cancel
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: [C1 Hostname#82a7f361:443 tcp, url hash: fe9d5b61, tls] cancelled
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>:  [C1.1 <private> 192.168.2.9:52264<->IPv4#ab6e0ca5:48083]
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>:  Connected Path: satisfied (Path is satisfied), interface: en2, ipv4, dns
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>:  Duration: 30.474s, , TCP @0.039s took 0.000s, TLS took 0.038s
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>:  bytes in/out: 3500/910, packets in/out: 6/4, rtt: 0.000s, retransmitted packets: 0, out-of-order packets: 0
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.000s [C1 <private> Hostname#82a7f361:443 proxy] path:start
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.000s [C1 <private> Hostname#82a7f361:443 proxy] proxy:start_process
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.000s [C1 <private> Hostname#82a7f361:443 proxy] proxy:finish_process
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.000s [C1 <private> Hostname#82a7f361:443 proxy] proxy:start_resolve
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.009s [C1 <private> Hostname#82a7f361:443 proxy] proxy:finish_resolve
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.009s [C1.1 <private> 192.168.2.9:52264<->IPv4#ab6e0ca5:48083 channel-flow] path:start
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.009s [C1.1 <private> 192.168.2.9:52264<->IPv4#ab6e0ca5:48083 channel-flow] path:satisfied
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.009s [C1.1 <private> 192.168.2.9:52264<->IPv4#ab6e0ca5:48083 channel-flow] flow:start_nexus
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.009s [C1.1 <private> 192.168.2.9:52264<->IPv4#ab6e0ca5:48083 channel-flow] flow:receive_nexus
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.009s [C1.1 <private> 192.168.2.9:52264<->IPv4#ab6e0ca5:48083 channel-flow] flow:start_connect
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.010s [C1.1 <private> 192.168.2.9:52264<->IPv4#ab6e0ca5:48083 channel-flow] flow:finish_transport
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.010s [C1 <private> Hostname#82a7f361:443 proxy] flow:finish_transport
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.010s [C1.1 <private> 192.168.2.9:52264<->IPv4#ab6e0ca5:48083 channel-flow] flow:finish_connect
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.010s [C1 <private> Hostname#82a7f361:443 proxy] flow:finish_connect
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.010s [C1.1 <private> 192.168.2.9:52264<->IPv4#ab6e0ca5:48083 channel-flow] flow:changed_viability
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.010s [C1 <private> Hostname#82a7f361:443 proxy] flow:changed_viability
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.039s [C1.1 <private> 192.168.2.9:52264<->IPv4#ab6e0ca5:48083 channel-flow] flow:start_secondary_connect
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.039s [C1 <private> Hostname#82a7f361:443 proxy] flow:start_secondary_connect
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.039s [C1.1 <private> 192.168.2.9:52264<->IPv4#ab6e0ca5:48083 channel-flow] flow:start_connect
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.039s [C1 <private> Hostname#82a7f361:443 proxy] flow:start_connect
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.039s [C1 <private> Hostname#82a7f361:443 proxy] flow:finish_transport
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.077s [C1.1 <private> 192.168.2.9:52264<->IPv4#ab6e0ca5:48083 channel-flow] flow:finish_connect
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 0.077s [C1 <private> Hostname#82a7f361:443 proxy] flow:finish_connect
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: 30.474s [C1] path:cancel
Sep 24 00:33:17 iPhone MyApplication(libusrtcp.dylib)[1545] <Notice>: nw_protocol_tcp_log_summary [C1.1:2] 
Sep 24 00:33:17 iPhone MyApplication(libusrtcp.dylib)[1545] <Notice>:   Init: 1, Conn_Time: 0.494ms, Syn's: 1, WR_T: 0/0, RD_T: 0/0, TFO: 0/0/0, ECN: 0/1/1, TS: 1
Sep 24 00:33:17 iPhone MyApplication(libusrtcp.dylib)[1545] <Notice>:   RTT_Cache: kernel, rtt_upd: 5, rtt: 0.468ms, rtt_var: 0.562ms rtt_nc: 0.000ms, rtt_var_nc: 0.000ms
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: nw_endpoint_flow_protocol_disconnected [C1.1 IPv4#ab6e0ca5:48083 cancelled channel-flow (null)] Output protocol disconnected
Sep 24 00:33:17 iPhone MyApplication(libnetwork.dylib)[1545] <Notice>: nw_connection_report_state_with_handler_locked [C1] reporting state cancelled
Sep 24 00:33:17 iPhone MyApplication(CFNetwork)[1545] <Notice>: TIC TCP Conn Destroyed [1:0x2811436c0]
Sep 24 00:33:18 iPhone MyApplication(AccessibilityUtilities)[1545] <Notice>: Will reevaluate code items and load any needed ax code items now
Sep 24 00:33:18 iPhone MyApplication(AccessibilityUtilities)[1545] <Notice>: found 0 axbundle(s) requiring load
Sep 24 00:33:18 iPhone MyApplication(AccessibilityUtilities)[1545] <Notice>: Finished loading ax code items
Sep 24 00:33:28 iPhone MyApplication(Foundation)[1545] <Error>: errors encountered while discovering extensions: Error Domain=PlugInKit Code=13 "query cancelled" UserInfo={NSLocalizedDescription=query cancelled}
Sep 24 00:33:28 iPhone MyApplication(Foundation)[1545] <Error>:     owner = <BSProcessHandle: 0x147f25890; PhotoPicker:1548; valid: YES>;
Sep 24 00:33:28 iPhone MyApplication(Foundation)[1545] <Error>:     flags = preventSuspend, preventIdleSleep, preventSuspendOnSleep;
Sep 24 00:33:28 iPhone MyApplication(Foundation)[1545] <Error>: }
Francesco Galgani
  • 6,137
  • 3
  • 20
  • 23

1 Answers1

1

Make sure the URL for native doesn't include the file: prefix. Also wrap the native code in the iOS native thread as explained here.

dispatch_sync(dispatch_get_main_queue(), ^{
    // your native code here...
});

I would recommend dispatch_async which is better but for that you would need to make the API asynchronous. E.g. convetVideo(file, target) and isFinished() which you can monitor in a thread.

Shai Almog
  • 51,749
  • 5
  • 35
  • 65
  • Thank you Shai, I confirm that removing the `file:` prefix and adding the `dispatch_sync` solve the issue: now I can see the preview of the video. About your suggestion to make the API asynchronous, if the purpose of this advice is to don't block the calling thread (that in this example is the Codename One EDT), is it the same if I call the native code from an EasyThread? In other words, if the caller thread is not the EDT, is there no requirement to use an async call? – Francesco Galgani Sep 24 '19 at 11:17
  • 1
    If you use a separate thread it's better because calling a blocking native thread API from the EDT is a deadlock waiting to happen. However, async calls are generally slower. If it's one image you can probably get away with it. But if you're making a thumbnail directory you might be better off with an API based on a callback or something like that. – Shai Almog Sep 25 '19 at 02:30