Dubbit: the cartoon creator app
About a year ago I was watching South Park and realized how hilarious the show was despite the simplicity of the animations. I then started to think about how many more funny stories could be told if anyone could make an animation, not just the handful of people at South Park Studios. I decided to find out and began building Dubbit, an animated cartoon creator app together with Soroush Pour. After we threw in a month or two of work, it was starting to come together and we launched a minimally viable product with a bare bones feature set to the Apple app store and the cartoons started pouring in from all around the world!
It was again one of those awesome builder moments when you release what you have been working on for a while and see people using it for the first time. Each laughing person we heard in the background of a cartoon voice-over made us smile, we had created something silly but also very special. I wanted to share with you some of the technical challenges of building Dubbit, as well as some of the cartoons our users created.
Video Uploads Are Slow
The biggest challenge to building Dubbit was having fast upload times for users who wanted to share their animated cartoons. At first we thought we could just record the phone screen and audio while they made the animation in app. For a 30 second cartoon, this resulted in a ~64MB MP4 file which even when compressed was still a lot of data to upload during app use. We resorted to recording the character coordinate points for each frame of the animation (30 times a second) so we had a detailed record of the animation at every frame of a 30 fps (frames per second) video. This file was a couple of kilobytes large and could be compressed together with the audio recording of the animation and uploaded to our backend server where we used pygame and FFMpeg to convert it into an actual video file.
Converting a coordinates file into a video file meant recreating each frame of the video from the coordinates using Pygame, saving these frames as images and then combining all the images into a video file and overlaying the audio so that it matched up with the animation. This brought down the upload time to under 2 seconds! Success!
We did however shift some of the waiting time to those who wanted to view the animation since transcoding and uploading it to Youtube took a couple seconds. In addition to this, another cost of speeding up the upload process was building the animations rendering engine on the server side which was a solid amount of work. It did however make the app very user-friendly and usable and was considered a necessary trade-off.
Push vs. Pull Transcoding
When we first created the video transcoder on the server side, we had a cron running every 5 seconds, looking for any unprocessed animations to transcode. Although this system worked, it was a very inefficient use of our compute, not to say anything of the potential lag time if your animation just missed the cron run. We quickly realized that a push system would work much better then polling the unprocessed queue at a regular interval. Enter ZeroMQ.
ZeroMQ is a concurrent networking library that makes it easy to connect sockets N-to-N with patterns such as fan-out, pub-sub, task distribution and request-reply. For Dubbit, we used their publisher-subscriber pattern to allow our video transcoder to be notified as soon as a new animation was available for processing. When the video transcoder gets this notification, it hands the job to one of 5 worker threads waiting for work. If all workers are busy, the job gets queued until the next worker is free to take it on. In this way, we can transcode 5 animations simultaneously and never drop a notification but rather queue them until they can be processed.
With this kind of architecture, it would have been very easy to scale both vertically and horizontally. We could easily move the process to a large EC2 instance and increase the number of worker threads running on any given machine. We could also switch from the pub-sub pattern to a parallel pipeline pattern, allowing us to have workers pull jobs on multiple instances from a single ventilator instance.
NSTimer Isn't Very Timely
While building the animations recorder class in our iOS app, we needed the coordinates of the characters to be recorded 30 times a second in order for us to then create a 30 fps video. In order to do this, we first tried using NSTimer to call the recordFrame method every 33.33 millisecond but quickly found that it was not in fact a real-time timer. In order to call recordFrame 30 times a second, we had to use CADisplayLink as follows:
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(recordFrame:)];
displayLink.frameInterval = 2;
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
CADisplay was intended as a timer object that allows applications to synchronise their drawing to the refresh rate of the display. Because of this, it really was a real-time timer and by setting frameInterval
to 2, it would call our method after every two frame refreshes, equivalent to 30 times a second.
User OnBoarding Is Non-trivial
When we first launched Dubbit, we would watch every animation someone created in order to learn about how users used the app. We quickly realized that many new users without us there to educate them on how to make an animation were clueless. Hundreds of silent cartoons without any voiceovers or talking characters made this painfully apparent. In order to fix this, we added a walk-through guide to the app, explaining to users how to make a Dubbit. Below is an animated gif of the responsive directions we gave users as they went through the necessary steps.
This simple addition increased dramatically the number of successful animations created. It was only a first step however and there were still many who weren't figuring out how to use Dubbit fast enough. There is still a lot of room for improvement in this aspect of the app.
The Average Person Isn't As Funny As South Park
One of the things we realized quite early on after launching Dubbit was that the average person really wasn't as funny as South Park. The saving grace of this realization however was that many things were only funny to those who knew the creators involved. It turns out a lot of humor stems from the personal relationship we have with the story teller and the specific inside jokes they reference in their animation. This limited amount of transferable comedic value made us think hard as to whether Dubbit should become more of a vine-type app where the best animations get voted into popularity or whether it should be a snapchat-like app between friends. With only such a simple incarnation of the idea, we were already learning an incredible amount about which future direction would make the most sense for this product.
Dubbit Cartoons From The World Over
Check out some of the cartoons people made using the Dubbit app! Enjoy!