Transcoding — proces konwersji cyfrowego pliku multimedialnego z jednego formatu kompresji na inny poprzez pełne dekodowanie i ponowne kodowanie. W przeciwieństwie do transmultipleksacji (zmiany tylko kontenera), transkodowanie zmienia kodek, bitrate, rozdzielczość i inne parametry skompresowanego strumienia. Według Apple AVFoundation documentation (2026), transkodowanie jest używane do adaptacji treści pod różne urządzenia i warunki sieciowe.
Najważniejsze
Transcoding — proces konwersji pliku multimedialnego z jednego formatu kompresji na inny poprzez pełne dekodowanie źródłowego strumienia do pośredniego nieskompresowanego formatu PCM, a następnie kodowanie z nowymi parametrami. Jeśli w źródłowym pliku wideo jest skompresowane kodekiem H.264 z bitratem 10 Mb/s, a na wyjściu potrzebny jest H.265 z bitratem 3 Mb/s — to jest transkodowanie.
Transkodowanie różni się od zwykłego przepakowywania (transmuxing), przy którym zmienia się tylko kontener (np. MP4 na MKV), a sam skompresowany strumień bitowy pozostaje niezmieniony. Podczas transkodowania zachodzą obliczeniowo kosztowne przekształcenia: dekodowanie każdej klatki, zastosowanie filtrów (skalowanie, korekcja kolorów, przycinanie), ponowne kodowanie z nowymi parametrami. To sprawia, że transkodowanie jest jedną z najbardziej zasobożernych operacji podczas pracy z mediami.
Transkodowanie znajduje zastosowanie w szerokim spektrum zadań: adaptacja wideo do ograniczeń przepustowości sieci, konwersja do formatu ze sprzętowym wsparciem dekodowania na urządzeniu docelowym, tworzenie wielu wersji dla streamingu HLS/DASH, wyodrębnianie ścieżek audio do osobnego pliku. Serwisy OTT (Netflix, YouTube, Twitch) transkodują każdy przesłany plik do dziesiątek wariantów z różnymi bitratami, rozdzielczościami i kodekami, aby zapewnić adaptacyjny streaming milionom użytkowników.
Proces transkodowania składa się z trzech głównych etapów: dekodowanie, przetwarzanie i kodowanie. Każdy etap może być wykonany zarówno na CPU, jak i na GPU/sprzętowych blokach, w zależności od dostępności i wymaganej wydajności.
Pierwszy etap — dekodowanie źródłowego strumienia. Plik źródłowy jest odczytywany z kontenera (MP4, MOV, MKV), po czym skompresowane pakiety wideo są kierowane do dekodera. Dekodowanie może być sprzętowe (jeśli kodek jest obsługiwany) lub programowe przez FFmpeg. Na wyjściu dekodowania otrzymuje się nieskompresowane klatki w formacie YUV420 lub BGRA — właśnie od tego etapu transkodowanie różni się od zwykłego remultipleksowania.
Drugi etap — filtracja i przetwarzanie. Zdekodowane klatki przechodzą przez łańcuch filtrów: skalowanie do docelowej rozdzielczości, zmiana częstotliwości klatek, korekcja kolorów, nakładanie tekstu lub grafiki. Łańcuch filtrów FFmpeg jest budowany jako graf, gdzie każdy filtr to osobny moduł przetwarzania. Na przykład filtr scale=1280:720 zmienia rozdzielczość, fps=30 zmienia częstotliwość klatek, a yadif wykonuje deinterlacing. Wszystkie operacje są wykonywane na nieskompresowanych klatkach, dlatego drugi etap jest najbardziej zasobożerny.
Trzeci etap — kodowanie do docelowego formatu. Przetworzone klatki są podawane na wejście enkodera, który kompresuje je zgodnie z algorytmem docelowego kodeka. Enkoder może być sprzętowy (VideoToolbox na iOS, MediaCodec na Android) lub programowy (libx264, libx265). Parametry kodowania: CRF (Constant Rate Factor) dla stałej jakości, bitrate dla CBR/VBR, profil i poziom dla kompatybilności z docelowymi urządzeniami.
// Schemat pipelineu transkodowania w FFmpeg
AVFormatContext *inputCtx, *outputCtx;
AVCodecContext *decoderCtx, *encoderCtx;
AVFrame *frame = av_frame_alloc();
AVPacket packet;
while (av_read_frame(inputCtx, &packet) >= 0) {
// 1. Dekodowanie
avcodec_send_packet(decoderCtx, &packet);
avcodec_receive_frame(decoderCtx, frame);
// 2. Filtrowanie (skalowanie + zmiana fps)
sws_scale(swsCtx, frame->data, frame->linesize,
0, frame->height, scaledFrame->data,
scaledFrame->linesize);
// 3. Kodowanie
avcodec_send_frame(encoderCtx, scaledFrame);
avcodec_receive_packet(encoderCtx, &outPacket);
av_interleaved_write_frame(outputCtx, &outPacket);
}
Przedstawiony pipeline demonstruje klasyczny cykl transkodowania. Funkcja av_read_frame odczytuje skompresowane pakiety z pliku wejściowego, avcodec_send_packet dekoduje je na klatki, sws_scale wykonuje skalowanie, a avcodec_send_frame koduje przetworzoną klatkę do formatu wyjściowego. Taki trzyetapowy cykl powtarza się dla każdej klatki lub grupy klatek (GOP), w zależności od ustawień enkodera.
Różnica między transkodowaniem a transmultipleksacją to jeden z najczęstszych punktów nieporozumień w inżynierii mediów. Zrozumienie tej różnicy jest kluczowe dla wyboru właściwej strategii przetwarzania mediów.
| Parametr | Transkodowanie | Transmultipleksacja |
|---|---|---|
| Co się zmienia | Kodek, bitrate, rozdzielczość | Kontener, metadane |
| Obciążenie obliczeniowe | Wysokie (dekodowanie + kodowanie) | Minimalne (kopiowanie pakietów) |
| Jakość | Może się pogorszyć (straty generacji) | Bezstratna |
| Czas wykonania | Minuty–godziny dla długiego wideo | Sekundy–minuty |
| Zastosowanie | Adaptacja formatu, kompresja | Zmiana kontenera dla kompatybilności |
Transmuxing — to przepakowanie skompresowanego strumienia do innego kontenera bez dekodowania i ponownego kodowania. Jeśli wideo jest już skompresowane kodekiem H.265 w kontenerze MP4 i trzeba je umieścić w kontenerze MOV lub MKV — transmultipleksacja po prostu kopiuje pakiety bitowe z jednego kontenera do drugiego. Jakość nie ulega pogorszeniu, czas przetwarzania jest minimalny, ponieważ nie wymaga dekodowania klatek. FFmpeg wykonuje transmultipleksację z flagą -codec copy.
Transkodowanie natomiast w pełni deszyfruje i ponownie kompresuje strumień multimedialny. Za każdym razem, gdy wideo przechodzi przez transkodowanie, może wystąpić strata generacji (generation loss) — nieznaczne pogorszenie jakości z powodu ponownej kompresji stratnej. Nawet przy tym samym bitracie trzecia generacja transkodowania jest zwykle gorsza od pierwszej. Dlatego profesjonaliści zalecają przechowywanie master-kopii w nieskompresowanych lub minimalnie skompresowanych formatach (ProRes, DNxHR) i transkodowanie tylko finalnych wersji do dostarczenia.
Wybór narzędzia do transkodowania zależy od platformy, wymagań wydajnościowych i scenariusza użycia. Do programowania mobilnego dostępne są zarówno natywne API, jak i biblioteki wieloplatformowe.
FFmpeg — standard de facto dla transkodowania na wszystkich platformach. Wiersz poleceń FFmpeg pozwala wykonywać praktycznie dowolne przekształcenia: zmiana kodeka, zmiana bitratu, przycinanie, łączenie, nakładanie filtrów. Do aplikacji mobilnych FFmpeg integruje się przez biblioteki libavformat, libavcodec i libavfilter. Przykład typowego polecenia transkodowania: ffmpeg -i input.mp4 -c:v libx265 -crf 23 -c:a aac -b:a 128k output.mp4.
Na iOS transkodowanie wykonuje się przez AVAssetWriter i AVAssetReader. AVAssetReader dekoduje plik źródłowy, odczytując nieskompresowane klatki, a AVAssetWriter koduje je do docelowego formatu. To podejście automatycznie wykorzystuje sprzętowe enkodery VideoToolbox, co zapewnia maksymalną wydajność. Na Androidzie analogiczna funkcjonalność jest dostępna przez MediaCodec w parze z MediaExtractor i MediaMuxer — MediaExtractor wyodrębnia skompresowane pakiety, MediaCodec dekoduje i koduje, MediaMuxer zapisuje wynik.
Do serwerowego transkodowania w środowisku produkcyjnym używa się usług chmurowych: AWS Elemental MediaConvert, Azure Media Services, Google Transcoder API. Te usługi automatycznie skalują się pod obciążeniem, obsługują wszystkie popularne formaty i mogą transkodować jeden plik wejściowy do dziesiątek wariantów wyjściowych do adaptacyjnego streamingu (HLS, DASH). Dla aplikacji mobilnych transkodowanie w chmurze jest optymalnym rozwiązaniem, ponieważ nie obciąża urządzenia użytkownika i pozwala przygotowywać treści asynchronicznie.
Rozważmy praktyczne przykłady transkodowania na platformach mobilnych z wykorzystaniem sprzętowego przyspieszenia i konfiguracją kluczowych parametrów jakości.
import AVFoundation
func transcodeVideo(sourceURL: URL, destURL: URL) {
let asset = AVAsset(url: sourceURL)
let preset = AVAssetExportPresetHEVCHighestQuality
AVAssetExportSession(asset: asset, presetName: preset)?
.exportAsynchronously {
switch assetExportSession?.status {
case .completed:
print("Transkodowanie zakończone")
case .failed:
print("Błąd: " + assetExportSession.error.localizedDescription)
default:
break
}
}
// Ręczne transkodowanie z AVAssetReader + AVAssetWriter
let reader = try AVAssetReader(asset: asset)
let writer = try AVAssetWriter(url: destURL,
fileType: .mp4)
let outputSettings: [String: Any] = [
AVVideoCodecKey: AVVideoCodecType.hevc,
AVVideoWidthKey: 1920,
AVVideoHeightKey: 1080,
AVVideoCompressionPropertiesKey: [
AVVideoAverageBitRateKey: 4_000_000,
AVVideoProfileLevelKey: AVVideoProfileLevelH265Main10
]
]
let adaptor = AVAssetWriterInput(
mediaType: .video,
outputSettings: outputSettings
)
writer.add(adaptor)
}
W przykładzie zastosowano dwa podejścia do transkodowania na iOS. AVAssetExportSession — prosty sposób z predefiniowanymi ustawieniami jakości (HEVCHighestQuality dla H.265). Ręczny pipeline przez AVAssetReader + AVAssetWriter daje pełną kontrolę nad parametrami: bitrate, profil, poziom. Parametr AVVideoProfileLevelH265Main10 włącza profil HDR Main10 z głębią kolorów 10 bitów, co jest ważne dla nowoczesnych treści HDR.
class Transcoder(private val context: Context) {
fun transcodeToHevc(inputUri: Uri, outputFile: File) {
val extractor = MediaExtractor()
extractor.setDataSource(context, inputUri, null)
val trackFormat = extractor.getTrackFormat(videoTrackIndex)
val mime = trackFormat.getString(MediaFormat.KEY_MIME)
val decoder = MediaCodec.createDecoderByType(mime!!)
val encoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_HEVC)
val outputFormat = MediaFormat.createVideoFormat(
MediaFormat.MIMETYPE_VIDEO_HEVC, 1920, 1080
).apply {
setInteger(MediaFormat.KEY_BIT_RATE, 4_000_000)
setInteger(MediaFormat.KEY_FRAME_RATE, 30)
setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2)
}
encoder.configure(outputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
encoder.start()
}
}
Kod na Androida tworzy pipeline z MediaExtractor — MediaCodec decoder — MediaCodec encoder — MediaMuxer. MediaExtractor określa typ kodeka z pliku wejściowego i wybiera odpowiedni dekoder. Enkoder jest konfigurowany na H.265 (HEVC) z bitratem 4 Mb/s i interwałem klatek kluczowych 2 sekund, co jest optymalne do streamingu. Ważne: MediaCodec encoder działa synchronicznie, dlatego do transkodowania w czasie rzeczywistym wymagane jest zorganizowanie pętli z poprawnym przetwarzaniem znaczników czasu (PTS) dla każdej klatki.
Transkodowanie na urządzeniach mobilnych to zadanie wymagające starannej optymalizacji ze względu na ograniczone zasoby CPU, GPU i ograniczenia termiczne. Kilka strategii pomaga wykonywać transkodowanie efektywnie.
Kluczowym czynnikiem wydajności jest sprzętowy enkoder. Na iOS VideoToolbox zapewnia sprzętowe kodowanie H.264 i H.265 z prędkością 5–10 razy większą niż programowy libx264. Na Androidzie MediaCodec używa sprzętowych komponentów OMX, jeśli są dostępne. Włączenie sprzętowego kodowania skraca czas transkodowania 10-minutowego wideo z 30–40 minut (programowo) do 3–5 minut (sprzętowo) na flagowym urządzeniu.
Dla mobilnego transkodowania kluczowa jest równowaga między jakością, rozmiarem i czasem przetwarzania. Dla H.265 na urządzeniach mobilnych zaleca się bitrate 4–8 Mb/s dla wideo 1080p z częstotliwością klatek 30 FPS. Tryb CRF (Constant Rate Factor) w libx265 pozwala ustawić jakość bezpośrednio, gdzie 23–28 daje dobrą jakość wizualną przy umiarkowanym rozmiarze pliku. Dla sprzętowych enkoderów należy używać trybu CBR z docelowym bitratem, ponieważ CRF nie jest obsługiwany sprzętowo.
Ciągłe transkodowanie na urządzeniu mobilnym powoduje znaczne nagrzewanie. Po 5–7 minutach intensywnego kodowania wideo 4K temperatura procesora może osiągnąć 50–55 stopni, po czym włącza się throttling. Rozwiązanie — transkodowanie z przerwami lub obniżenie częstotliwości klatek do 30 FPS. Jeśli aplikacja wymaga masowego transkodowania (np. edytor wideo), lepiej wykonywać przetwarzanie partiami po 2–3 minuty z przerwami na chłodzenie. Dla scenariuszy produkcyjnych optymalnie jest przenieść transkodowanie na stronę serwerową i korzystać z usług chmurowych.
Często zadawane pytania
Kodowanie (encoding) — kompresja źródłowych nieskompresowanych danych do docelowego kodeka. Transkodowanie obejmuje zarówno dekodowanie, jak i kodowanie: najpierw dekoduje istniejący skompresowany strumień, a następnie koduje go ponownie. Zwykłe kodowanie przyjmuje na wejściu nieskompresowane dane (na przykład z kamery), a transkodowanie — już skompresowany plik.
Dla maksymalnej kompatybilności — H.264. Dla lepszej kompresji — H.265 (HEVC). Jeśli urządzenie obsługuje sprzętowe kodowanie H.265 (iPhone 8+, Android z Snapdragon 845+), zapewnia ono dwukrotnie mniejszy rozmiar pliku przy tej samej jakości. Kodowanie AV1 na urządzeniach mobilnych jest wciąż zbyt wolne, nawet ze sprzętowym przyspieszeniem.
Ściśle rzecz biorąc, transkodowanie bezstratne jest niemożliwe przy zmianie kodeka stratnego. Jeśli oba kodeki są stratne, każde kolejne pokolenie transkodowania pogarsza jakość. Transkodowanie bezstratne jest możliwe tylko między formatami bezstratnymi (FFV1, H.264 Lossless) lub przy zmianie kontenera bez przekodowywania (transmuxing).
Tak, jeśli używane są sprzętowe dekoder i enkoder, a docelowa rozdzielczość nie przekracza 1080p. Na urządzeniach z VideoToolbox (iOS) lub MediaCodec (Android) transkodowanie w czasie rzeczywistym H.264 do H.265 jest możliwe z opóźnieniem 1–3 sekund. Dla 4K w czasie rzeczywistym wymagany jest wydajny SoC Apple A17 Pro, Snapdragon 8 Gen 2 lub nowszy.
Transkodowanie stratne kumuluje artefakty kompresji. Jeśli plik źródłowy był już silnie skompresowany (bitrate 2–3 Mb/s dla 1080p), ponowna kompresja podwoi straty. Zaleca się transkodowanie tylko z master-kopii o wysokim bitracie (20+ Mb/s) i używanie CRF 18–23 dla minimalnych strat.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również