Under the white flag post, or How I saved your video course from appearing on the tracker

Under the white flag post, or How I saved your video course from appearing on the tracker


captain_barbossa.jpg

Hi, Habr! Hmm, I have the feeling that we have already met ... Oh, yes. Here is the post where we discussed the lamp condition of whether it is acceptable to monitor the environment, limit the user in the number of devices to view, provide executables files instead of paid-up videos and behaving differently in every other way when organizing the "protection" of video courses from piracy.

And all would be nothing, but that's just not to criticize, not offering in return his decision. "You can do better, or what?!" , - exclamations were heard from the comments. “It would be better to support the compatriot, to help make their product better!” , - I briefly retell some general thoughts. Fair. So, I really can do better . At the very least, my proposal will not require the end user to launch a curved software instead of the expected video files.

Solving all problems


And the solution is the most trivial, friends: watermarks. Yes, just watermarks. Instead of inventing complex binding mechanisms for a specific device, “sign” the video sequence. That’s all.

What properties should a watermark have in order to perform a defensive function:

  1. Watermark must contain information that uniquely identifies the user who purchased the video course. This can be an activation key issued to the user, or a username obtained when registering on the video course purchase site, or time stamps corresponding to the course purchase time (of course, if you can unambiguously correlate them with the buyer's personality), or anything from this opera.
  2. Watermark should cover most of the frame so that it cannot be cut without major losses for the video course.
  3. The layout of the watermark should be random for each copy of the course, so that the villain does not write an automaton for cutting out the watermark itself.

If you make a watermark highly transparent, its presence does not interfere with the user, but still it is worth mentioning this in the course description before paying .

Thus, to extract incriminating information, a potential pirate would need to go through one of the scenarios described below:

  1. Cut the watermark entirely (remember that according to the 2nd property, the watermark should occupy the entire screen and continue to perform its protective functions even if it is partially erased), thereby devaluing the video (in my opinion, it is logical that in the case where there is not a large part of the video, there is no value of the video).
  2. Edit each frame separately to get rid of the watermark without causing significant damage to the video. The complexity of performing such an action manually exceeds the creation of a video from scratch, and according to the 3rd property, the offender is unable to automate the process.
  3. (?) Probably, you can ask a smart neural network to do it for you. Although not sure, not an expert, you can correct me in the comments.

Proof-of-Concept


For half an hour, a trivial script of 100 lines was compiled, demonstrating the simplicity and accessibility of the implementation of such protection. I emphasize : not to show how clever I am, but even quite the opposite, to note that a person very far from image processing could create a completely working code in half an hour (under the spoiler) , that's how simple it is:

fckInfoprotectorV2.py
  #!/usr/bin/env  python3
 # - * - coding: utf-8 - * -

 # Usage: python3 fckInfoprotectorV2.py

 import os
 from shutil import rmtree

 import numpy as np
 import cv2


 class VideoSigner:

 def __init __ (self, video, watermark):
  os.makedirs ('original')
  os.makedirs ('watermarked')

  self.vidin = cv2.VideoCapture (video)
  self.fps = self.vidin.get (cv2.CAP_PROP_FPS)
  self.frame_size = (
  int (self.vidin.get (cv2.CAP_PROP_FRAME_WIDTH)),
  int (self.vidin.get (cv2.CAP_PROP_FRAME_HEIGHT))
  )

  self.watermark = cv2.imread (watermark, cv2.IMREAD_UNCHANGED)
  self.wH, self.wW = self.watermark.shape [: 2]

  B, G, R, A = cv2.split (self.watermark)
  B = cv2.bitwise_and (B, B, mask = A)
  G = cv2.bitwise_and (G, G, mask = A)
  R = cv2.bitwise_and (R, R, mask = A)
  self.watermark = cv2.merge ([B, G, R, A])

 def __del __ (self):
  rmtree ('original')
  rmtree ('watermarked')

 def _split (self):
  print ('[*] Splitting video by frames ...', end = '', flush = True)

  (success, image), count = self.vidin.read (), 0
  while success:
  path = os.path.join ('original', f '{count} .jpg')
  cv2.imwrite (path, image)
  success, image = self.vidin.read ()
  count + = 1

  print ('Done')

 def _watermark (self):
  print ('[*] Signing each frame ...', end = '', flush = True)

  for image_name in sorted (
  os.listdir ('original'),
  key = lambda x: int (x.split ('.') [0])
  ):
  image_path = os.path.join ('original', image_name)
  image = cv2.imread (image_path)
  h, w = image.shape [: 2]

  image = np.dstack ([
  image,
  np.ones ((h, w), dtype = 'uint8') * 255
  ])

  overlay = np.zeros ((h, w, 4), dtype = 'uint8')
  half_h_diff = (h - self.wH)//2
  half_w_diff = (w - self.wW)//2
  overlay [half_h_diff: half_h_diff + self.wH, half_w_diff: half_w_diff + self.wW] = self.watermark

  output = image.copy ()
  cv2.addWeighted (overlay, 0.25, output, 1.0, 0, output)

  path = os.path.join ('watermarked', image_name)
  cv2.imwrite (path, output)

  print ('Done')

 def _merge (self):
  print ('[*] Merging signed frames ...', end = '', flush = True)

  self.vidout = cv2.VideoWriter (
  'signed.avi',
  cv2.VideoWriter_fourcc (* 'XVID'),
  fps = self.fps,
  frameSize = self.frame_size
  )

  for image_name in sorted (
  os.listdir ('watermarked'),
  key = lambda x: int (x.split ('.') [0])
  ):
  image_path = os.path.join ('watermarked', image_name)
  image = cv2.imread (image_path)
  self.vidout.write (image)

  print ('Done')

 def sign (self):
  self._split ()
  self._watermark ()
  self._merge ()


 if __name__ == '__main__':
 signer = VideoSigner ('SampleVideo_1280x720_1mb.mp4', 'watermark.png')
 signer.sign ()
  


The result of the script, on the this sample as an example:

sample_original.gif

sample_signed.gif


Not for the sake of hype, but only for the common good.

I have the honor.

Source text: Under the white flag post, or How I saved your video course from appearing on the tracker