Uma postagem com bandeira branca ou Como eu salvei seu curso em vídeo de aparecer no rastreador

captain_barbossa.jpg

Olá Habr! Hum, sinto que já nos conhecemos ... Ah, sim. Aqui está o post em que discutimos levianamente se é aceitável monitorar o ambiente, limitar o usuário ao número de dispositivos para visualização, fornecer arquivos executáveis ​​em vez de vídeos pagos e se comportar de maneira diferente de todas as maneiras possíveis ao organizar a "proteção" dos cursos de vídeo contra a pirataria.

E tudo ficaria bem, mas é impossível criticar sem propor uma solução em troca. "Você pode fazer melhor?" - exclamações dos comentários foram ouvidas. "Seria melhor apoiar um compatriota, ajudar a melhorar seu produto!" - Reconto brevemente alguns pensamentos gerais. Justo. Então, eu realmente posso fazer melhor . No mínimo, minha proposta não exigirá que o usuário final execute software torto em vez dos arquivos de vídeo esperados.

Solução para todos os problemas


E a solução é dos amigos mais triviais: marcas d'água. Sim, apenas marcas d'água. Em vez de criar mecanismos complexos para vincular a um dispositivo específico, "assine" a sequência de vídeo. Só isso.

Quais propriedades uma marca d'água deve ter para desempenhar uma função defensiva:

  1. A marca d'água deve conter informações que identifiquem exclusivamente o usuário que comprou o curso em vídeo. Pode ser uma chave de ativação emitida para o usuário, ou o login do usuário obtido no momento do registro no site de compra do curso em vídeo, ou os horários correspondentes ao horário da compra do curso (é claro, se você puder correlacioná-los de maneira inequívoca com a identidade do comprador) ou qualquer coisa desta ópera.
  2. A marca d'água deve cobrir a maior parte do quadro, para que não possa ser cortada sem grandes perdas para o curso de vídeo.
  3. O esquema de sobreposição de marcas d'água deve ser aleatório para cada cópia do curso, para que o vilão não escreva uma máquina automatizada para cortar a mesma marca d'água.

Se você tornar a marca d'água muito transparente, sua presença não interferirá no usuário, mas ainda vale a pena mencionar isso na descrição do curso antes do pagamento .

Assim, para extrair informações reveladoras, um pirata em potencial precisaria seguir um dos cenários descritos abaixo:

  1. Recorte a marca d'água inteira (lembre-se de que, de acordo com a 2ª propriedade, a marca d'água deve ocupar a tela inteira e continuar desempenhando suas funções de proteção mesmo se parcialmente apagada), invalidando o videoclipe (na minha opinião, é lógico que, no caso de não haver mais) vídeo, não há valor para o vídeo).
  2. Edite cada quadro individualmente para se livrar da marca d'água, sem causar danos significativos ao vídeo. A complexidade de executar essa ação manualmente excede a criação de um vídeo a partir do zero e, de acordo com a 3ª propriedade, o invasor não tem a capacidade de automatizar o processo.
  3. (?) Acho que você pode solicitar uma rede neural inteligente para fazer isso por você. Embora não tenha certeza, não seja um especialista, você pode me corrigir nos comentários.

Prova de conceito


Em meia hora, um script trivial de 100 linhas foi compilado, demonstrando a simplicidade e acessibilidade da implementação dessa proteção. Enfatizo : para não mostrar o quão inteligente eu sou, mas mesmo o oposto, observar que uma pessoa que está muito longe do processamento de imagens conseguiu compor um código totalmente funcional (sob o spoiler) em meia hora, é assim que é simples:

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() 


O resultado do script, neste exemplo como um exemplo:

sample_original.gif

sample_signed.gif


Não por hype, mas apenas pelo bem comum.

Eu tenho a honra.

Source: https://habr.com/ru/post/pt450344/


All Articles