KalyanChakravarthy.net

Thoughts, stories and ideas.

Xcode: Keyboard shortcuts for assistant editor

Most of the time I just need 2 code panes on my main monitor, for which using ⌥⌘↩ or Option-Command-↩ usually does the job. Sometimes I need to see more than 2 files on the same screen and I always keep forgetting how to do that in Xcode. Here is it on record for posterity.

There are 2 ways

  1. View -> Assistant Editor -> Add Assistant editor
  2. Command-Shift-O -> Select file -> Command+J

FFMPEG: Simple video editing

As I started shooting videos from my drone, a pattern I repeatedly see is that I want to extract bits of a video for posting. Since I can't be bothered to install dedicated video editing tools to do that, am learning how to do that in ffmpeg. Turns out it is pretty straight forward

Cut video

:::shell
$ ffmpeg -i <InputVideo.mp4>\ 
    -ss <start_from_seconds>\
    -t <end_at_seconds>\
    -c copy 
    <OutputVideo.mp4>
  • -ss startfromseconds - this is the start time point in original video
  • -t endatseconds - end time point in the original video

Add Audio

This works by selecting 2 inputs and composing the output with stream selection using -map. Eg: -map 0:v selects video stream from first input. -shortest makes the output length be the shortest of the two inputs (which usually is the case for my videos). Finally we specify the OutputFile.mp4 where we want it to go.

:::shell
$ ffmpeg -i VideoInput.mp4\
    -i AudioInput.mp3\
    -map 0:v\
    -map 1:a\ 
    -c copy\
    -shortest\
    OutputFile.mp4

Adding Fadeout

Once I have the video slice with audio added, the last part to add a nice fade out effect. I prefer to start reducing the volume of audio first and then start fading video out to black. Here is a small piece of shell code that helps with that.

:::shell
# Video Fade duration in seconds
v_fade_duration=2 

# Audio fade duration
a_fade_duration=4 

# Obtain from shell or set for actual values
input_file=$1 
output_file=$2

# probe the duration to help compute actual start point in video
duration=$(ffprobe -select_streams v -show_streams "$1" 2>/dev/null |
    awk -F= '$input_file == "duration"{print $2}')
v_final_cut=$(bc -l <<< "$duration - $v_fade_duration")
a_final_cut=$(bc -l <<< "$duration - $a_fade_duration")

# magic
ffmpeg -i "$1" \
    -filter:v "fade=out:st=$v_final_cut:d=$v_fade_duration" \
    -af "afade=t=out:st=$a_final_cut:d=$a_fade_duration" \
    -c:v libx264 -crf 22 -preset veryfast -strict -2 "$output_file"

Result

Dispatch Sources: Timer

Dispatch souces define an event source that when triggered can invoke a pre-defined callback. Instead of registering for events and then writing logic to handle events to make a callback, dispatch source can be used.

Dispatch timer

For example, with interval timers, its not trivial to setup NSTimer outside of main threads as it requires a run-loop with predictable lifetime. Using a runloop outside main thread is painful. Dispatch queues have ephimeral threads and as such are bad candidates for use with NSTimers.

This is a scenario where dispatch source is an ideal use-case. A dispatch timer source, fires an event when the time interval has been completed, which then fires a pre-set callback all on the same queue.

// Define a queue
queue = dispatch_queue_create("com.blah",0);

// Define timer
interval_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

// Configure timer with type(wallclock), interval(2 mins), leeway(5)
// leeway is acceptable error
dispatch_source_set_timer( interval_timer, dispatch_walltime(NULL,0), 2*60, 5 );

// Callback when timer is fired
dispatch_source_set_event_handler(interval_timer, ^{
    NSLog(@"Timer event");
}); 

It is also easy to start and suspend timer events. Its as simple as calling

dispatch_resume( interval_timer );
dispatch_suspend( interval_timer );

Dispatch After

If an event needs to be fired after a time interval, but does not require cancellation, it is simpler to just use dispatch_after

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<delayInSeconds> * NSEC_PER_SEC)), <queue>, ^{
    // code to be executed after a specified delay
});

Example: Flushing Queue after time interval

Here is some pseudo/sample code that consumes objects via -addEvent: until - either the object count becomes <N>, or <T> seconds have elapsed since last object add and in the end calls -flush:

@implementation KCTimer
{
    dispatch_source_t _interval_timer;
    dispatch_queue_t _flush_queue;
    NSUInteger _count;
    NSUInteger _timelimit;
}

- (instancetype) initWithCount:(NSUInteger)count andTimeLimit:(NSUInteger)limit 
{
    if( self = [super init] ) {
        _timelimit = limit;
        _count = count;

        _flush_queue = dispatch_queue_create("com.blah",0);
        _interval_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, flush_queue);
        dispatch_source_set_event_handler(_interval_timer, ^{
            [self flush];
        }); 
        [self reset];
        [self resume];
    }
    return self;
}

- (void)resume
{
    dispatch_resume( _interval_timer );
}

- (void)suspend
{
    dispatch_suspend( _interval_timer );
}

- (void)reset
{
    dispatch_source_set_timer( interval_timer, dispatch_walltime(NULL,0), _timelimit, 5 );
}

- (void)addEvent:(Event *)e 
{
    // TODO: Add stuff in thread safe manner
    [self reset];
    if(eventCount >= 50) {
        dispatch_async(flush_queue,^{
            [self flush];
        });
    }
}

- (void)flush
{
    // TODO: Flush queue in thread safe manner
}

Go-lang Notes

Declarations

Sometimes its hard to believe that this is indeed a compiled language, mostly due to type inference. In most cases you do not need to specify type in declarative initialization unless you are just declaring.

var someInt int; // type required
anotherInt := 23 // type not required

Type inference is only available inside functions and not in top level declarations. The designers state that it is by design to optimise for faster compilation.

Arrays & Maps

Coming from python and objective-c, I always took for granted that I can dump in any type of object into either an array or a dictionary/map; This is not something you can do in Go and I initially presumed this might become an obstacle. I was surprised to note that I felt no need for it at all, yet.

The syntax seemed complicated initiaially, but its its quite simple if you know how go synatax goes

// Declaring
var Mapping map[string]string;
Mapping = make(map[string]string)

// string maps to string
var Dictionary := make(map[string]string)

// String maps to *Route
var RouteMapping := make(map[string]*Route)

Types

Everything outside the realm of simple functions almost always involves types. They have to be used for

  1. structs (for oop-ish things)

    type TinyServer struct {}
    
  2. aliases a.k.a typedefs

    type TinyConnectionHandler func(*TinyConnection)
    
  3. interfaces

    type TinyServerHandler interface {}
    

Structs/OOP

Golang is not particularly object oriented. It is possible to achieve the notion of it using structs, associated methods and composition.

Composition Example:

type Connection struct {
    ResponseWriter http.ResponseWriter
    Request  *http.Request
}

type TinyConnection struct {
    Connection
    Url *url.URL
    Vars map[string]string
}

This makes all methods as well as variables from Connection available in TinyConnection struct. Trying to override a method will cause a compile time error.

Associated Methods:

func (connection *Connection) WriteString(content string) {
    fmt.Fprintf(connection.ResponseWriter, content)
}

At first look the syntax may look quite odd especially if you are coming from other languages like python. But I found it to be quite similar to C++, with the exception of position of return which in Go is at the end.

:::cpp
void Connection::WriteString(char *string){
    //blah
}

Interfaces

Another oddity of golang is how interfaces are implemented - You declare an interface and its contents, but you never explicitly specify if a struct/class implements an interface. Consider this example:

:::go
type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

type MyHandler struct {}
func (MyHandler *h) ServeHTTP(ResponseWriter, *Request) {}

The struct MyHandler is assumed to implement the interface Handler just because it implements ServeHTTP method. It almost feels like its duck typing, although attempting to assign handler directly will cause compile error.

:::go
type Server struct {
    handler Handler
}

myHandler := &MyHandler{}
server := &Server{}
server.handler = myHandler // compiler error

The only way to do the above assignment is to create a new instance of the interface and assign the pointer value

handler := new(Handler)
*handler = myHandler
server.handler = *handler

Regexp

An amusing aspects of the regexp module is that the method naming conforms to a regex. Straight from godoc:

There are 16 methods of Regexp that match a regular expression and identify the matched text. Their names are matched by this regular expression:

Find(All)?(String)?(Submatch)?(Index)?

Multiple returns

functions can return multiple values. This although is part of the language, its not very different from returning a tuple in python

:::python
def returnTwoThings():
    return (1,2)    
a, _ = returnTwoThings()

Go

:::go
func returnTwoThings() (int,int) {
    return (1,2)
}
a, _ := returnTwoThings()

Only major difference is in go, the return types have to be explicitly declared. This means one can't arbitrarily decide to return 3 items unlike python.

Main

Go does not compile to a binary executable unless there is a main package and there exists a main() function.

Garbage Collection

The language is designed to be garbage collected. So the binary ships with a GC. Although this is great if the final main() is in go, its not useful if you'd like to use your go code to work with something written and compiled C.

In short: You can import C code into Go. The vice versa is not possible, yet. There goes my dream of building a mac/ios app in golang.

Detect touches on words in UILabels

Detecting touches on UIViews is quite trivial. But trying to recognize touches on individual words or attributed strings can be not so much, which was exactly what I wanted to do.

There are 2 approaches one can take

  • CoreText and compute the frames of all glyphs
  • TextKit - which is not exactly kit per se, but are bunch of classes part of UIKit

TextKit

TextKit is designed based on MVC, with:

  • M being NSTextStorage
  • V being NSTextContainer
  • C being NSLayoutManager

NSTextStorage acts as the data provider and can own multiple NSLayoutManagers. For the layout manager to display text, it needs an instance of NSTextContainer, which essentially defines the area of visible text.

NSTextContainer has 2 main properties defining the layout - the bounds and the exclusion paths. Bounds is the outline rect, this is required. Optionally one can pass a bezier path to define which areas are not to be layouted - allowing one flow text around images.

Here is some code that detects touch on "Read More" string of a UILabel*.

:::objc

/*
    Some initialization
*/
- (void)viewDidLoad {
    // The full string
    NSMutableDictionary *attributesForString = [[NSMutableDictionary alloc] init];
    attributesForString[ NSFontAttributeName ] = [UIFont systemFontOfSize:13];
    self.attrString = [[NSMutableAttributedString alloc] initWithString:@"Lorem ipsum dolor set amit"];

    // The "Read More" string that should be touchable
    attributesForString[ NSFontAttributeName ] = [UIFont boldSystemFontOfSize:13];
    self.moreString = [[NSAttributedString alloc] initWithString:@"READ MORE" attributes:attributesForString];
    [self.attrString appendAttributedString:self.moreString];

    // Store range of chars we want to detect touches for
    self.moreStringRange = [self.attrString.string rangeOfString:self.moreString.string];

    self.textLabel.attributedString = self.attrString;

    UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self selector:@selector(didTap:)];
    [self.textLabel addGestureRecgonizer:tapRecognizer];
}

/*
    Simple touch recognition.
    Could be setup during initialisation.
*/
- (void)didTap:(UITapGestureRecognizer *)gesture {
    // Storage class stores the string, obviously
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self.attrString];

    // The storage class owns a layout manager
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
    [textStorage addLayoutManager:layoutManager];

    // Layout manager owns a container which basically
    // defines the bounds the text should be contained in
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:self.textLabel.frame.size];

    // For labels the fragment padding should be 0
    textContainer.lineFragmentPadding = 0;

    // Begin computation of actual frame
    // Glyph is the final display representation
    // Eg: Ligatures have 2 characters but only 1 glyph.
    NSRange glyphRange;

    // Extract the glyph range
    [layoutManager characterRangeForGlyphRange:self.moreStringRange actualGlyphRange:&glyphRange];

    // Compute the rect of glyph in the text container
    CGRect glyphRect = [layoutManager boundingRectForGlyphRange:glyphRange inTextContainer:textContainer];

    // Final rect relative to the textLabel.
    NSLog( @"%@", glyphRect );

    // Now figure out if the touch point is inside our rect
    CGPoint touchPoint = [gesture locationOfTouch:0 inView:self.textLabel];

    if( CGRectContainsPoint(glyphRect, touchPoint) ) {
        NSLog( @"User tapped on Read More. So show something more");
    }
}