Skip to content

Latest commit

 

History

History
76 lines (52 loc) · 2.52 KB

File metadata and controls

76 lines (52 loc) · 2.52 KB

00 - Teaser

On April 16, the sixth edition of the Hacky Easter competition is going to start! Check out the promo video!

In order to sweeten the waiting time, we are providing a teaser challenge in advance. Download the video file below, and find the teaser Easter egg.

he2019_teaser.zip

Solution

Provided ZIP archive contained a high framerate MP4 video file.

$ unzip he2019_teaser.zip 
Archive:  he2019_teaser.zip
  inflating: he2019_teaser.mp4
$ ffmpeg -i he2019_teaser.mp4 -hide_banner
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'he2019_teaser.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2mp41
    encoder         : Lavf58.17.101
  Duration: 00:00:05.00, start: 0.000000, bitrate: 15905 kb/s
    Stream #0:0(und): Video: mpeg4 (Simple Profile) (mp4v / 0x7634706D), yuv420p, 100x100 [SAR 1:1 DAR 1:1], 14190 kb/s, 46080.20 fps, 46080 tbr, 46080 tbn, 46080 tbc (default)
    Metadata:
      handler_name  : VideoHandler

The video consisted only of fast blinking frames of uniform color. I decided to extract the frames to inspect them.

$ ffmpeg -i he2019_teaser.mp4 frames/frame%06d.jpg -hide_banner

There were 230.400 of them. I noticed that the number was equal to the square of 480, which could mean that it was an animated sequence pixels of an image of dimensions 480x480. I wrote a Scala program which reconstructed the image pixel by pixel from the extracted frames.

val workdir = Paths.get("hackyeaster2019/challenges/teaser/files/frames").toAbsolutePath

val egg = reconstructImage(Files.newDirectoryStream(workdir).asScala.toList.sorted)

saveImage(egg, workdir.getParent.resolve("egg.png"))

def reconstructImage(frames: List[Path]): BufferedImage = {
  val size = math.sqrt(frames.size).toInt
  val image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB)

  val graphics = image.getGraphics

  frames.zipWithIndex.foreach { case (file, idx) =>
    val xpos = idx % size
    val ypos = idx / size

    val frame = loadImage(file)
    val color = new Color(frame.getRGB(0, 0))

    graphics.setColor(color)
    graphics.drawRect(xpos, ypos, 1, 1)
  }

  graphics.dispose()

  image
}

def loadImage(path: Path): BufferedImage = ImageIO.read(path.toFile)

def saveImage(image: BufferedImage, path: Path): Unit = ImageIO.write(image, "png", path.toFile)

The complete source code can be found here.

Egg

egg.png