Python kullanarak video sıkıştırma algoritmalarını sıfırdan anlama ve uygulama için kapsamlı bir rehber. Modern video codec'lerinin arkasındaki teori ve pratiği öğrenin.
Python ile Video Codec Oluşturma: Sıkıştırma Algoritmalarına Derinlemesine Bir Bakış
Hiper bağlantılı dünyamızda video kraldır. Akış hizmetlerinden video konferanslara ve sosyal medya akışlarına kadar, dijital video internet trafiğine hakimdir. Ancak yüksek çözünürlüklü bir filmi standart bir internet bağlantısı üzerinden göndermek nasıl mümkün oluyor? Cevap, büyüleyici ve karmaşık bir alanda yatıyor: video sıkıştırma. Bu teknolojinin kalbinde, görsel kaliteyi korurken dosya boyutunu büyük ölçüde azaltmak için tasarlanmış gelişmiş bir algoritma kümesi olan video codec (COder-DECoder) bulunur.
H.264, HEVC (H.265) ve telifsiz AV1 gibi endüstri standardı codec'ler inanılmaz derecede karmaşık mühendislik parçaları olsa da, temel prensiplerini anlamak her motive geliştirici için erişilebilirdir. Bu rehber sizi video sıkıştırma dünyasının derinliklerine bir yolculuğa çıkaracak. Sadece teoriden bahsetmeyeceğiz; sıfırdan basitleştirilmiş, eğitici bir video codec'i Python kullanarak inşa edeceğiz. Bu uygulamalı yaklaşım, modern video akışını mümkün kılan zarif fikirleri kavramanın en iyi yoludur.
Neden Python? Gerçek zamanlı, yüksek performanslı ticari bir codec için kullanacağınız bir dil olmasa da (bunlar genellikle C/C++ veya hatta assembly ile yazılır), Python'ın okunabilirliği ve NumPy, SciPy ve OpenCV gibi güçlü kütüphaneleri onu öğrenme, prototipleme ve araştırma için mükemmel bir ortam haline getirir. Düşük seviyeli bellek yönetimine takılmadan algoritmalara odaklanabilirsiniz.
Video Sıkıştırmanın Temel Kavramlarını Anlamak
Tek bir kod satırı yazmadan önce, neyi başarmaya çalıştığımızı anlamalıyız. Video sıkıştırmanın amacı, gereksiz verileri ortadan kaldırmaktır. Ham, sıkıştırılmamış bir video devasadır. Saniyede 30 kare hızında bir dakikalık 1080p video 7 GB'ı aşabilir. Bu veri canavarını evcilleştirmek için iki ana tür fazlalığı kullanırız.
Sıkıştırmanın İki Temel Direği: Mekansal ve Zamansal Fazlalık
- Mekansal (Kare İçi) Fazlalık: Bu, tek bir kare içindeki fazlalıktır. Geniş bir mavi gökyüzü yaması veya beyaz bir duvar düşünün. Bu alandaki her bir piksel için renk değerini depolamak yerine, onu daha verimli bir şekilde tanımlayabiliriz. Bu, JPEG gibi görüntü sıkıştırma formatlarının arkasındaki aynı prensiptir.
- Zamansal (Kareler Arası) Fazlalık: Bu, ardışık kareler arasındaki fazlalıktır. Çoğu videoda sahne bir kareden diğerine tamamen değişmez. Örneğin, statik bir arka plana karşı konuşan bir kişinin büyük miktarda zamansal fazlalığı vardır. Arka plan aynı kalır; görüntünün sadece küçük bir kısmı (kişinin yüzü ve vücudu) hareket eder. Bu, videodaki en önemli sıkıştırma kaynağıdır.
Anahtar Kare Türleri: I-kareler, P-kareler ve B-kareler
Zamansal fazlalığı kullanmak için codec'ler her kareye eşit davranmaz. Onları farklı türlere ayırarak Resim Grubu (GOP) adı verilen bir dizi oluştururlar.
- I-kare (Intra-kodlu Kare): I-kare, eksiksiz, kendi kendine yeten bir görüntüdür. Yalnızca mekansal fazlalık kullanılarak, tıpkı bir JPEG gibi sıkıştırılır. I-kareler, video akışında bir referans noktası görevi görür ve bir izleyicinin oynatmayı başlatmasına veya yeni bir konuma geçmesine olanak tanır. En büyük kare türüdür ancak videoyu yeniden oluşturmak için gereklidir.
- P-kare (Tahmini Kare): P-kare, önceki I-kareye veya P-kareye bakılarak kodlanır. Resmin tamamını depolamak yerine, yalnızca farklılıkları depolar. Örneğin, "bu piksel bloğunu son kareden al, 5 piksel sağa taşı ve küçük renk değişiklikleri şunlar" gibi talimatları depolar. Bu, hareket tahmini adı verilen bir işlemle gerçekleştirilir.
- B-kare (Çift Yönlü Tahmini Kare): B-kare en verimli olanıdır. Hem önceki hem de sonraki kareleri tahmin için referans olarak kullanabilir. Bu, bir nesnenin geçici olarak gizlendiği ve sonra tekrar göründüğü sahneler için kullanışlıdır. İleri ve geri bakarak, codec daha doğru ve veri açısından verimli bir tahmin oluşturabilir. Ancak, gelecek kareleri kullanmak küçük bir gecikme (latency) getirir, bu da onları video görüşmeleri gibi gerçek zamanlı uygulamalar için daha az uygun hale getirir.
Tipik bir GOP şöyle görünebilir: I B B P B B P B B I .... Kodlayıcı, sıkıştırma verimliliği ve arama yeteneğini dengelemek için optimal kare modeline karar verir.
Sıkıştırma Süreci: Adım Adım Bir Analiz
Modern video kodlama, çok aşamalı bir süreçtir. Her aşama, verileri daha sıkıştırılabilir hale getirmek için dönüştürür. Tek bir kareyi kodlamak için ana adımlara göz atalım.

Adım 1: Renk Uzayı Dönüşümü (RGB'den YCbCr'ye)
Çoğu video RGB (Kırmızı, Yeşil, Mavi) renk uzayında başlar. Ancak, insan gözü parlaklıktaki (luma) değişikliklere, renkteki (kroma) değişikliklere olduğundan çok daha duyarlıdır. Codec'ler, RGB'yi YCbCr gibi bir luma/kroma formatına dönüştürerek bunu kullanır.
- Y: Luma bileşeni (parlaklık).
- Cb: Mavi-fark kroma bileşeni.
- Cr: Kırmızı-fark kroma bileşeni.
Parlaklığı renkten ayırarak, kroma alt örneklemesi uygulayabiliriz. Bu teknik, gözlerimizin en hassas olduğu parlaklık kanalı (Y) için tam çözünürlüğü korurken, renk kanallarının (Cb ve Cr) çözünürlüğünü azaltır. Yaygın bir şema olan 4:2:0, neredeyse hiç algılanabilir kalite kaybı olmadan renk bilgisinin %75'ini atar ve anında sıkıştırma sağlar.
Adım 2: Kare Bölümlendirme (Makrobloklar)
Kodlayıcı tüm kareyi bir kerede işlemez. Kareyi, tipik olarak 16x16 veya 8x8 piksel boyutlarında, makroblok adı verilen daha küçük bloklara böler. Sonraki tüm işleme adımları (tahmin, dönüşüm vb.) blok bazında gerçekleştirilir.
Adım 3: Tahmin (Kare İçi ve Kareler Arası)
Burası işin sihri gerçekleştiği yer. Her makroblok için kodlayıcı, kare içi veya kareler arası tahmin kullanıp kullanmayacağına karar verir.
- Bir I-kare için (Kare İçi tahmin): Kodlayıcı, mevcut bloğu, aynı kare içindeki önceden kodlanmış komşu piksellerine (üst ve solundaki bloklar) dayanarak tahmin eder. Daha sonra sadece tahmin ile gerçek blok arasındaki küçük farkı (rezidüel) kodlaması gerekir.
- Bir P-kare veya B-kare için (Kareler Arası tahmin): Bu, hareket tahminidir. Kodlayıcı, referans bir karede eşleşen bir blok arar. En iyi eşleşmeyi bulduğunda, bir hareket vektörü (örn. "10 piksel sağa, 2 piksel aşağı taşı") kaydeder ve rezidüeli hesaplar. Genellikle, rezidüel sıfıra yakındır ve kodlamak için çok az bit gerektirir.
Adım 4: Dönüşüm (Örn. Ayrık Kosinüs Dönüşümü - DCT)
Tahminden sonra, bir rezidüel bloğumuz olur. Bu blok, Ayrık Kosinüs Dönüşümü (DCT) gibi matematiksel bir dönüşümden geçirilir. DCT, veriyi kendisi sıkıştırmaz, ancak nasıl temsil edildiğini temelden değiştirir. Uzamsal piksel değerlerini frekans katsayılarına dönüştürür. DCT'nin büyüsü, çoğu doğal görüntü için görsel enerjinin çoğunu bloğun sol üst köşesindeki (düşük frekanslı bileşenler) sadece birkaç katsayıda yoğunlaştırmasıdır, diğer katsayılar (yüksek frekanslı gürültü) ise sıfıra yakındır.
Adım 5: Niceleme
Bu, süreçteki birincil kayıplı adımdır ve kalite-bit hızı dengesini kontrol etmenin anahtarıdır. DCT katsayılarının dönüştürülmüş bloğu bir niceleme matrisine bölünür ve sonuçlar en yakın tam sayıya yuvarlanır. Niceleme matrisi, yüksek frekanslı katsayılar için daha büyük değerlere sahiptir ve bunların çoğunu etkili bir şekilde sıfıra indirir. Verinin büyük bir kısmı burada atılır. Daha yüksek bir niceleme parametresi, daha fazla sıfıra, daha yüksek sıkıştırmaya ve daha düşük görsel kaliteye (genellikle bloklu artefaktlar olarak görülür) yol açar.
Adım 6: Entropi Kodlama
Son aşama kayıpsız bir sıkıştırma adımıdır. Nicelenmiş katsayılar, hareket vektörleri ve diğer meta veriler taranır ve ikili bir akışa dönüştürülür. Çalışma Uzunluğu Kodlaması (RLE) ve Huffman Kodlaması veya CABAC (Bağlama Uyarlamalı İkili Aritmetik Kodlama) gibi daha gelişmiş yöntemler kullanılır. Bu algoritmalar, daha sık görülen sembollere (niceleme ile oluşturulan birçok sıfır gibi) daha kısa kodlar, daha az sık görülen sembollere ise daha uzun kodlar atayarak veri akışından son bitleri sıkıştırır.
Çözücü bu adımları sadece tersine çevirir: Entropi Çözme -> Ters Niceleme -> Ters Dönüşüm -> Hareket Telafisi -> Kareyi Yeniden Yapılandırma.
Python'da Basitleştirilmiş Bir Video Codec Uygulaması
Şimdi teoriyi pratiğe dökelim. I-kareler ve P-kareler kullanan eğitici bir codec oluşturacağız. Temel süreci gösterecek: Hareket Tahmini, DCT, Niceleme ve ilgili çözme adımları.
Yasal Uyarı: Bu, öğrenmek için tasarlanmış bir *oyuncak* codec'tir. Optimize edilmemiştir ve H.264 ile karşılaştırılabilir sonuçlar üretmeyecektir. Amacımız algoritmaları iş başında görmektir.
Ön Koşullar
Aşağıdaki Python kütüphanelerine ihtiyacınız olacak. Bunları pip kullanarak kurabilirsiniz:
pip install numpy opencv-python scipy
Proje Yapısı
Kodumuzu birkaç dosyaya ayıralım:
main.py: Kodlama ve çözme sürecini çalıştıran ana betik.encoder.py: Kodlayıcının mantığını içerir.decoder.py: Çözücünün mantığını içerir.utils.py: Video G/Ç ve dönüşümler için yardımcı fonksiyonlar.
Bölüm 1: Temel Yardımcı Programlar (utils.py)
DCT, Niceleme ve bunların tersleri için yardımcı fonksiyonlarla başlayacağız. Ayrıca bir kareyi bloklara ayırmak için bir fonksiyona da ihtiyacımız olacak.
# utils.py
import numpy as np
from scipy.fftpack import dct, idct
BLOCK_SIZE = 8
# A standard JPEG quantization matrix (scaled for our purposes)
QUANTIZATION_MATRIX = np.array([
[16, 11, 10, 16, 24, 40, 51, 61],
[12, 12, 14, 19, 26, 58, 60, 55],
[14, 13, 16, 24, 40, 57, 69, 56],
[14, 17, 22, 29, 51, 87, 80, 62],
[18, 22, 37, 56, 68, 109, 103, 77],
[24, 35, 55, 64, 81, 104, 113, 92],
[49, 64, 78, 87, 103, 121, 120, 101],
[72, 92, 95, 98, 112, 100, 103, 99]
])
def apply_dct(block):
"""Applies 2D DCT to a block."""
# Center the pixel values around 0
block = block - 128
return dct(dct(block.T, norm='ortho').T, norm='ortho')
def apply_idct(dct_block):
"""Applies 2D Inverse DCT to a block."""
block = idct(idct(dct_block.T, norm='ortho').T, norm='ortho')
# De-center and clip to valid pixel range
return np.round(block + 128).clip(0, 255)
def quantize(dct_block, qp=1):
"""Quantizes a DCT block. qp is a quality parameter."""
return np.round(dct_block / (QUANTIZATION_MATRIX * qp)).astype(int)
def dequantize(quantized_block, qp=1):
"""Dequantizes a block."""
return quantized_block * (QUANTIZATION_MATRIX * qp)
def frame_to_blocks(frame):
"""Splits a frame into 8x8 blocks."""
blocks = []
h, w = frame.shape
for i in range(0, h, BLOCK_SIZE):
for j in range(0, w, BLOCK_SIZE):
blocks.append(frame[i:i+BLOCK_SIZE, j:j+BLOCK_SIZE])
return blocks
def blocks_to_frame(blocks, h, w):
"""Reconstructs a frame from 8x8 blocks."""
frame = np.zeros((h, w), dtype=np.uint8)
k = 0
for i in range(0, h, BLOCK_SIZE):
for j in range(0, w, BLOCK_SIZE):
frame[i:i+BLOCK_SIZE, j:j+BLOCK_SIZE] = blocks[k]
k += 1
return frame
Bölüm 2: Kodlayıcı (encoder.py)
Kodlayıcı en karmaşık kısımdır. Hareket tahmini için basit bir blok eşleştirme algoritması uygulayacak ve ardından I-kareleri ve P-kareleri işleyeceğiz.
# encoder.py
import numpy as np
from utils import apply_dct, quantize, frame_to_blocks, BLOCK_SIZE
def get_motion_vectors(current_frame, reference_frame, search_range=8):
"""A simple block matching algorithm for motion estimation."""
h, w = current_frame.shape
motion_vectors = []
for i in range(0, h, BLOCK_SIZE):
for j in range(0, w, BLOCK_SIZE):
current_block = current_frame[i:i+BLOCK_SIZE, j:j+BLOCK_SIZE]
best_match_sad = float('inf')
best_match_vector = (0, 0)
# Search in the reference frame
for y in range(-search_range, search_range + 1):
for x in range(-search_range, search_range + 1):
ref_i, ref_j = i + y, j + x
if 0 <= ref_i <= h - BLOCK_SIZE and 0 <= ref_j <= w - BLOCK_SIZE:
ref_block = reference_frame[ref_i:ref_i+BLOCK_SIZE, ref_j:ref_j+BLOCK_SIZE]
sad = np.sum(np.abs(current_block - ref_block))
if sad < best_match_sad:
best_match_sad = sad
best_match_vector = (y, x)
motion_vectors.append(best_match_vector)
return motion_vectors
def encode_iframe(frame, qp=1):
"""Encodes an I-frame."""
h, w = frame.shape
blocks = frame_to_blocks(frame)
quantized_blocks = []
for block in blocks:
dct_block = apply_dct(block.astype(float))
quantized_block = quantize(dct_block, qp)
quantized_blocks.append(quantized_block)
return {'type': 'I', 'h': h, 'w': w, 'data': quantized_blocks, 'qp': qp}
def encode_pframe(current_frame, reference_frame, qp=1):
"""Encodes a P-frame."""
h, w = current_frame.shape
motion_vectors = get_motion_vectors(current_frame, reference_frame)
quantized_residuals = []
k = 0
for i in range(0, h, BLOCK_SIZE):
for j in range(0, w, BLOCK_SIZE):
current_block = current_frame[i:i+BLOCK_SIZE, j:j+BLOCK_SIZE]
mv_y, mv_x = motion_vectors[k]
ref_block = reference_frame[i+mv_y : i+mv_y+BLOCK_SIZE, j+mv_x : j+mv_x+BLOCK_SIZE]
residual = current_block.astype(float) - ref_block.astype(float)
dct_residual = apply_dct(residual)
quantized_residual = quantize(dct_residual, qp)
quantized_residuals.append(quantized_residual)
k += 1
return {'type': 'P', 'motion_vectors': motion_vectors, 'data': quantized_residuals, 'qp': qp}
Bölüm 3: Çözücü (decoder.py)
Çözücü süreci tersine çevirir. P-kareler için, depolanan hareket vektörlerini kullanarak hareket telafisi yapar.
# decoder.py
import numpy as np
from utils import apply_idct, dequantize, blocks_to_frame, BLOCK_SIZE
def decode_iframe(encoded_frame):
"""Decodes an I-frame."""
h, w = encoded_frame['h'], encoded_frame['w']
qp = encoded_frame['qp']
quantized_blocks = encoded_frame['data']
reconstructed_blocks = []
for q_block in quantized_blocks:
dct_block = dequantize(q_block, qp)
block = apply_idct(dct_block)
reconstructed_blocks.append(block.astype(np.uint8))
return blocks_to_frame(reconstructed_blocks, h, w)
def decode_pframe(encoded_frame, reference_frame):
"""Decodes a P-frame using its reference frame."""
h, w = reference_frame.shape
qp = encoded_frame['qp']
motion_vectors = encoded_frame['motion_vectors']
quantized_residuals = encoded_frame['data']
reconstructed_blocks = []
k = 0
for i in range(0, h, BLOCK_SIZE):
for j in range(0, w, BLOCK_SIZE):
# Decode the residual
dct_residual = dequantize(quantized_residuals[k], qp)
residual = apply_idct(dct_residual)
# Perform motion compensation
mv_y, mv_x = motion_vectors[k]
ref_block = reference_frame[i+mv_y : i+mv_y+BLOCK_SIZE, j+mv_x : j+mv_x+BLOCK_SIZE]
# Reconstruct the block
reconstructed_block = (ref_block.astype(float) + residual).clip(0, 255)
reconstructed_blocks.append(reconstructed_block.astype(np.uint8))
k += 1
return blocks_to_frame(reconstructed_blocks, h, w)
Bölüm 4: Hepsini Bir Araya Getirme (main.py)
Bu betik tüm süreci düzenler: bir videoyu okuma, kare kare kodlama ve ardından nihai bir çıktı üretmek için çözme.
# main.py
import cv2
import pickle # For saving/loading our compressed data structure
from encoder import encode_iframe, encode_pframe
from decoder import decode_iframe, decode_pframe
def main(input_path, output_path, compressed_file_path):
cap = cv2.VideoCapture(input_path)
frames = []
while True:
ret, frame = cap.read()
if not ret:
break
# We'll work with the grayscale (luma) channel for simplicity
frames.append(cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY))
cap.release()
# --- ENCODING --- #
print("Encoding...")
compressed_data = []
reference_frame = None
gop_size = 12 # I-frame every 12 frames
for i, frame in enumerate(frames):
if i % gop_size == 0:
# Encode as I-frame
encoded_frame = encode_iframe(frame, qp=2.5)
compressed_data.append(encoded_frame)
print(f"Encoded frame {i} as I-frame")
else:
# Encode as P-frame
encoded_frame = encode_pframe(frame, reference_frame, qp=2.5)
compressed_data.append(encoded_frame)
print(f"Encoded frame {i} as P-frame")
# The reference for the next P-frame needs to be the *reconstructed* last frame
if encoded_frame['type'] == 'I':
reference_frame = decode_iframe(encoded_frame)
else:
reference_frame = decode_pframe(encoded_frame, reference_frame)
with open(compressed_file_path, 'wb') as f:
pickle.dump(compressed_data, f)
print(f"Compressed data saved to {compressed_file_path}")
# --- DECODING --- #
print("\nDecoding...")
with open(compressed_file_path, 'rb') as f:
loaded_compressed_data = pickle.load(f)
decoded_frames = []
reference_frame = None
for i, encoded_frame in enumerate(loaded_compressed_data):
if encoded_frame['type'] == 'I':
decoded_frame = decode_iframe(encoded_frame)
print(f"Decoded frame {i} (I-frame)")
else:
decoded_frame = decode_pframe(encoded_frame, reference_frame)
print(f"Decoded frame {i} (P-frame)")
decoded_frames.append(decoded_frame)
reference_frame = decoded_frame
# --- WRITING OUTPUT VIDEO --- #
h, w = decoded_frames[0].shape
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_path, fourcc, 30.0, (w, h), isColor=False)
for frame in decoded_frames:
out.write(frame)
out.release()
print(f"Decoded video saved to {output_path}")
if __name__ == '__main__':
main('input.mp4', 'output.mp4', 'compressed.bin')
Sonuçları Analiz Etme ve Daha Fazlasını Keşfetme
main.py betiğini bir input.mp4 dosyasıyla çalıştırdıktan sonra iki dosya alacaksınız: özel sıkıştırılmış video verilerimizi içeren compressed.bin ve yeniden oluşturulmuş video olan output.mp4. Sıkıştırma oranını görmek için input.mp4 boyutunu compressed.bin ile karşılaştırın. Kaliteyi görmek için output.mp4'ü görsel olarak inceleyin. Özellikle daha yüksek bir qp değeriyle bloklu artefaktlar görme olasılığınız yüksektir, bu da nicelemenin klasik bir işaretidir.
Kaliteyi Ölçme: Tepe Sinyal-Gürültü Oranı (PSNR)
Yeniden yapılandırma kalitesini ölçmek için yaygın bir nesnel metrik PSNR'dir. Orijinal kareyi çözülmüş kareyle karşılaştırır. Daha yüksek bir PSNR genellikle daha iyi kaliteyi gösterir.
import numpy as np
import math
def calculate_psnr(original, compressed):
mse = np.mean((original - compressed) ** 2)
if mse == 0:
return float('inf')
max_pixel = 255.0
psnr = 20 * math.log10(max_pixel / math.sqrt(mse))
return psnr
Sınırlamalar ve Sonraki Adımlar
Basit codec'imiz harika bir başlangıç noktası, ancak mükemmel olmaktan çok uzak. İşte gerçek dünya codec'lerinin evrimini yansıtan bazı sınırlamalar ve potansiyel iyileştirmeler:
- Hareket Tahmini: Kapsamlı arayışımız yavaş ve basittir. Gerçek codec'ler, hareket vektörlerini çok daha hızlı bulmak için sofistike, hiyerarşik arama algoritmaları kullanır.
- B-kareler: Sadece P-kareleri uyguladık. B-kareler eklemek, artan karmaşıklık ve gecikme maliyetiyle sıkıştırma verimliliğini önemli ölçüde artıracaktır.
- Entropi Kodlama: Uygun bir entropi kodlama aşaması uygulamadık. Python veri yapılarını basitçe paketledik. Nicelenmiş sıfırlar için Çalışma Uzunluğu Kodlayıcı ve ardından bir Huffman veya Aritmetik kodlayıcı eklemek dosya boyutunu daha da azaltacaktır.
- Blok Bozunma Filtresi: 8x8 bloklarımız arasındaki keskin kenarlar görünür artefaktlara neden olur. Modern codec'ler, bu kenarları yumuşatmak ve görsel kaliteyi iyileştirmek için yeniden yapılandırmadan sonra bir blok bozunma filtresi uygular.
- Değişken Blok Boyutları: Modern codec'ler sadece sabit 16x16 makroblokları kullanmaz. İçeriğe daha iyi uyum sağlamak için kareyi uyarlamalı olarak çeşitli blok boyutlarına ve şekillerine ayırabilirler (örn. düz alanlar için daha büyük bloklar ve ayrıntılı alanlar için daha küçük bloklar kullanma).
Sonuç
Basitleştirilmiş bile olsa bir video codec oluşturmak, dijital yaşamlarımızın önemli bir bölümünü sağlayan teknolojiyi gizemini çözmek açısından derinlemesine ödüllendirici bir egzersizdir. Mekansal ve zamansal fazlalığın temel kavramları boyunca yolculuk yaptık, kodlama sürecinin temel aşamalarından — tahmin, dönüşüm ve niceleme — geçtik ve bu fikirleri Python'da uyguladık.
Burada sağlanan kod bir başlangıç noktasıdır. Sizi onunla denemeler yapmaya teşvik ediyorum. Blok boyutunu, niceleme parametresini (qp) veya GOP uzunluğunu değiştirmeyi deneyin. Basit bir Çalışma Uzunluğu Kodlama şeması uygulamayı veya hatta B-kareler ekleme zorluğunu üstlenmeyi deneyin. Bir şeyler inşa ederek ve bozarak, genellikle hafife aldığımız sorunsuz video deneyimlerinin arkasındaki dahiliği derinden takdir edeceksiniz. Video sıkıştırma dünyası engin ve sürekli gelişiyor, öğrenme ve yenilik için sonsuz fırsatlar sunuyor.