Software decoding — processen för dekomprimering av mediadata med centralprocessorn (CPU) med hjälp av mjukvarubibliotek, utan användning av SoC:s hårdvarublocker. Mjukvaruavkodare är implementerade som plattformsoberoende bibliotek: FFmpeg med libavcodec och dav1d för AV1. Enligt FFmpeg-dokumentation (2026) stöder libavcodec över 200 codecs, vilket gör software decoding till det enda sättet att spela upp sällsynta format.
Huvudpunkter
Software decoding — ett sätt att dekomprimera mediadata där alla beräkningsoperationer utförs på CPU:s universella kärnor. Till skillnad från hårdvaruavkodning där varje codec har ett dedikerat fysiskt block, är en mjukvaruavkodare vanlig kod som utför samma algoritmer med processorinstruktioner.
Mjukvaruavkodare skrivs i C/C++ med optimeringar för specifika CPU-arkitekturer: SIMD-instruktioner ARM NEON för mobila enheter, Intel SSE/AVX för stationära datorer. Biblioteket libavcodec från FFmpeg innehåller tiotusentals rader optimerad assemblerkod för olika plattformar, vilket gör att mjukvaruavkodning kan uppnå hyfsad prestanda även för tunga format som AV1 på kraftfulla CPU:er.
Den främsta fördelen med mjukvaruavkodning är universalitet. Om en hårdvaruavkodare bara stöder 4–5 grundläggande format (H.264, H.265, VP9, AV1), kan FFmpeg avkoda över 200 codecs: från moderna AV1 och H.265 till arkivformat som Sorenson Spark, RealVideo och Motion JPEG. Detta gör mjukvaruavkodning till ett oumbärligt verktyg för applikationer som arbetar med icke-standardiserade mediadata — till exempel professionella videoredigerare, videoövervakningssystem och specialiserade spelare.
Mjukvaruavkodning upprepar samma steg som hårdvaruavkodning, men på en universell CPU. Varje steg implementeras som funktioner som anropas i följd för varje makroblock eller bildruta. Den viktigaste skillnaden är flexibilitet: utvecklaren kan ändra pipeline, lägga till filter och efterbehandling mellan avkodningsstegen.
En typisk mjukvaruavkodare består av moduler som implementerar separata steg i algoritmen. Entropiavkodningsmodulen läser bitströmmen och rekonstruerar de kvantiserade DCT-koefficienterna. För H.264 implementerar denna modul CABAC (Context-Adaptive Binary Arithmetic Coding) — en komplex algoritm med villkorliga förgreningar som är svår att accelerera med hårdvara, men som körs effektivt på en CPU med en bra branch predictor.
Den inversa kvantiseringsmodulen multiplicerar koefficienterna med kvantiseringssteget, och den inversa DCT-modulen tillämpar den diskreta cosinustransformen. Mjukvaruimplementationen av invers DCT använder den snabba Chen-algoritmen eller Loeffler-algoritmen, som minskar antalet multiplikations-ackumuleringsoperationer från 4096 till 256 för ett 8x8-block. SIMD-instruktioner NEON (ARM) eller SSE (x86) gör det möjligt att bearbeta 4–8 koefficienter i en instruktion, vilket ger en 4–8-faldig acceleration jämfört med skalär kod.
Rörelsekompensationsmodulen — den mest minneskrävande. Den extraherar områden från referensbildrutor enligt rörelsevektorer och tillämpar subpixelinterpolation. För H.265 når interpolationsnoggrannheten 1/8 pixel, vilket kräver filtrering med ett 8-taps FIR-filter för luminans och 4-taps för krominans. Mjukvaruimplementationen tvingas ladda stora mängder referensbilddata från cachen, vilket gör rörelsekompensationen till en flaskhals vid avkodning av höga upplösningar på CPU:n.
Moderna mobila processorer, som Apple A17 eller Qualcomm Snapdragon 8 Gen 2, har 6–8 kärnor med tillräcklig prestanda för mjukvaruavkodning av 1080p H.264 utan att hoppa över bildrutor. För 4K-innehåll, särskilt i formaten H.265 och AV1, kan mjukvaruavkodning på CPU:n dock inte hänga med: den typiska belastningen på alla kärnor når 70–90%, vilket är kritiskt för multitasking. Stora kärnor (Apple Performance, Qualcomm Kryo Prime) ger ~4–5x prestanda jämfört med små energieffektiva kärnor, men förbrukar proportionellt mer energi.
Marknaden för mjukvaruavkodare representeras av flera viktiga bibliotek, var och en optimerad för sin nisch. Valet av avkodare beror på vilka format som krävs, plattform och licensbegränsningar.
FFmpeg — de facto-standarden för mjukvaruavkodning i branschen. Biblioteket libavcodec innehåller avkodare för alla större och de flesta sällsynta codecs, stöder alla containrar (MP4, MKV, AVI, MOV, WebM) och fungerar på alla plattformar. FFmpeg är licensierat under LGPL/GPL, vilket kräver hänsyn till licensvillkoren vid kommersiell användning. På mobila enheter används FFmpeg via wrapper: ffmpeg-kit för iOS och Android, mobile-ffmpeg för React Native.
Dav1d — en mjukvaruavkodare för AV1 från VideoLAN (skaparna av VLC), skriven i C med SIMD-optimeringar. Dess huvudsakliga uppgift är snabbast möjliga mjukvaruavkodning av AV1 på CPU utan hårdvarustöd. Dav1d är 30–50% snabbare än referensavkodaren libaom från Alliance for Open Media tack vare aggressiva optimeringar: manuell cachehantering, användning av JIT-kompilering för efterbehandlingsfilter och vektorisering av kritiska funktioner.
På mobila enheter kan dav1d avkoda 1080p AV1 i realtid på flaggskepps-SoC:er (Apple A16+, Snapdragon 8 Gen 2+), men för 4K krävs en kraftfull CPU. Till exempel på Apple M1 når mjukvaru-dav1d ~60 FPS för 4K AV1, och på Snapdragon 8 Gen 2 — ~35 FPS. För stabil 4K AV1-uppspelning på mobila enheter rekommenderas fortfarande hårdvarustöd.
| Avkodare | Format | Plattformar | Licens |
|---|---|---|---|
| libavcodec | 200+ codecs | Alla | LGPL/GPL |
| dav1d | AV1 | Alla | BSD 2-Clause |
| libaom | AV1 | Alla | BSD 2-Clause |
| MediaFoundation | H.264, H.265 | Windows | Proprietär |
Valet mellan mjukvaru- och hårdvaruavkodning är en kompromiss mellan kompatibilitet och effektivitet. Tabellen nedan visar en detaljerad jämförelse av de viktigaste egenskaperna.
| Parameter | Software Decoding | Hardware Decoding |
|---|---|---|
| Stödda format | 200+ codecs | 4–6 codecs |
| Strömförbrukning | 1,5–5 W | 0,2–0,8 W |
| Anpassning | Full kontroll över pipeline | Endast via API |
| Fördröjning | 30–80 ms | 5–15 ms |
| Värmeutveckling | Hög (45–50 °C) | Låg (35–40 °C) |
| Codec-uppdatering | Via biblioteksuppdatering | Endast med ny SoC |
Mjukvaruavkodning ger maximal flexibilitet: utvecklaren kan modifiera algoritmer, lägga till anpassade filter, implementera egna bearbetningskedjor. Till exempel i videoredigeringsprogram kan varje avkodningssteg omdirigeras till GPU:n för färgkorrigering eller effekttillämpning — detta är endast möjligt med mjukvarukontroll över avkodningen.
Priset för flexibilitet är dock strömförbrukningen. För mobila enheter med ett batteri på 3000–5000 mAh minskar kontinuerlig mjukvaruavkodning visningstiden från 10–15 timmar (hårdvara) till 2–4 timmar. Uppvärmning av CPU till 45–50 grader kan också orsaka throttling — sänkning av processorfrekvensen för att skydda mot överhettning, vilket leder till överhoppade bildrutor och försämrad användarupplevelse.
Låt oss titta på praktisk implementering av mjukvaruavkodning på båda mobila plattformarna. På iOS används mjukvaruavkodning via FFmpeg, på Android — via samma bibliotek med en Java/Kotlin-wrapper.
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
class SoftwareDecoder {
AVCodecContext* codecCtx;
public:
bool init(const char* filename) {
AVFormatContext* fmtCtx = nullptr;
avformat_open_input(&fmtCtx, filename, nullptr, nullptr);
avformat_find_stream_info(fmtCtx, nullptr);
int videoStream = av_find_best_stream(
fmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0
);
AVCodec* decoder = avcodec_find_decoder(
fmtCtx->streams[videoStream]->codecpar->codec_id
);
codecCtx = avcodec_alloc_context3(decoder);
avcodec_parameters_to_context(codecCtx,
fmtCtx->streams[videoStream]->codecpar);
avcodec_open2(codecCtx, decoder, nullptr);
return true;
}
AVFrame* decodePacket(AVPacket* packet) {
avcodec_send_packet(codecCtx, packet);
AVFrame* frame = av_frame_alloc();
int ret = avcodec_receive_frame(codecCtx, frame);
return (ret >= 0) ? frame : nullptr;
}
};
Koden visar en minimal FFmpeg-pipeline för mjukvaruavkodning. avformat_open_input öppnar filen och bestämmer containerformatet, avcodec_find_decoder hittar automatiskt lämplig avkodare för valfri codec. Metoden decodePacket använder det nya API:et (avcodec_send_packet / avcodec_receive_frame), som stöder flertrådad avkodning när flaggan AV_CODEC_FLAG_LOW_DELAY är aktiverad för realtidsapplikationer.
class SoftwareDecoder(private val context: Context) {
fun decodeVideo(inputPath: String, outputFolder: String) {
val cmd = "-i $inputPath -vf fps=1 $outputFolder/frame_%04d.jpg"
FFmpegExecutor(context).executeCommand(cmd) { rc ->
Log.d("Avkodare", "Slutförd med rc: $rc")
}
}
fun getFrameCount(filePath: String): Int {
val probe = MediaMetadataRetriever()
probe.setDataSource(filePath)
val duration = probe.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_DURATION
)?.toIntOrNull() ?: 0
val fps = probe.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT
)?.toIntOrNull() ?: 0
probe.release()
return fps
}
}
Exemplet i Kotlin använder FFmpegExecutor för att extrahera en bildruta per sekund från video. Parametern -vf fps=1 skapar ett filter som hoppar över 59 av 60 bildrutor, vilket minskar CPU-belastningen. Detta tillvägagångssätt är användbart för att skapa förhandsvisningar och placeholders i mobila applikationer. För realtids-mjukvaruavkodning rekommenderas att använda lågnivå-API:et libavcodec direkt via JNI.
#include <dav1d/dav1d.h>
int decode_av1_frame(const uint8_t* data, size_t size) {
Dav1dContext* ctx = nullptr;
Dav1dSettings settings = { 0 };
dav1d_default_settings(&settings);
settings.n_threads = 4;
dav1d_open(&ctx, &settings);
Dav1dData dav1d_data = { 0 };
dav1d_data_wrap(&dav1d_data, data, size, nullptr, nullptr);
Dav1dPicture pic = { 0 };
if (dav1d_send_data(ctx, &dav1d_data) == 0) {
dav1d_get_picture(ctx, &pic);
}
dav1d_close(&ctx);
return pic.p.w;
}
Dav1d tillhandahåller ett minimalistiskt API: dav1d_open skapar en avkodarkontext med angivet antal trådar, dav1d_send_data tar emot den komprimerade bitströmmen, dav1d_get_picture returnerar den avkodade bildrutan i YUV420-format. För mobila enheter är det optimala antalet trådar (n_threads) antalet produktiva CPU-kärnor minus ett, för att lämna resurser till UI-tråden. Dav1d stöder också Dav1dPicAllocator för minneshantering och att undvika onödiga kopieringar vid överföring av bildrutan till GPU:n.
Trots den högre strömförbrukningen är mjukvaruavkodning oumbärlig i en rad scenarier där hårdvaruavkodning inte kan ge den nödvändiga funktionaliteten. Förståelse för dessa scenarier hjälper utvecklaren att fatta arkitekturbeslut.
Hårdvaruavkodare stöder bara moderna format. Om applikationen arbetar med arkivinspelningar, videoövervakning (MJPEG, H.263), professionella codecs (ProRes, DNxHD, CineForm) eller innehåll från tredje part — kommer mjukvaruavkodning via FFmpeg att vara det enda alternativet. ProRes avkodas i mjukvara på alla enheter utom Apple A13+-chips med hårdvarustöd. För H.263 finns inget hårdvarustöd på någon modern SoC — endast mjukvaruavkodning.
Mjukvaruavkodning ger full tillgång till varje steg i bildrutebehandlingen. Detta är avgörande för applikationer där filter (oskärpa, brusreducering, skärpning) måste appliceras direkt på avkodad data före utmatning. FFmpeg-filter gör det möjligt att bygga komplexa kedjor: avkodning -> färgkorrigering -> skalning -> textöverlägg -> kodning — allt inom ett enda bibliotek utan dataöverföring mellan olika API:er.
Den rekommenderade arkitekturen för en mediaspelare är hybrid: hårdvaruavkodning som primär, mjukvaruavkodning som fallback. Före uppspelning kontrollerar applikationen tillgängligheten av hårdvaruavkodaren för den specifika codecen. Om avkodaren inte hittas — startas mjukvaruavkodning via FFmpeg. Denna strategi säkerställer maximal kompatibilitet utan prestandaförlust för grundläggande format. Tillgänglighetskontrollen bör utföras vid varje start, eftersom hårdvarustöd kan variera även på enheter av samma modell på grund av olika SoC-revisioner.
Vanliga frågor
CPU:n är en universell processor som utför många olika uppgifter. För avkodning använder den delade beräkningsblock och cacheminne som förbrukar energi även när den utför en enda uppgift. Hårdvaruavkodaren är en specialiserad krets med en fast pipeline där varje transistor bara är involverad i avkodning, vilket radikalt minskar strömförbrukningen.
För H.264/H.265 — libavcodec från FFmpeg med aktiverade SIMD-optimeringar. För AV1 — dav1d, som är 30–50% snabbare än referens-libaom. På mobila enheter gör dav1d:s prestanda det möjligt att avkoda 1080p AV1 i realtid på flaggskepps-SoC:er (A16+, Dimensity 9200+).
Ja, FFmpeg är porterat till båda plattformarna. För iOS, använd ffmpeg-kit — en färdig build med stöd för alla codecs och format. För Android — mobile-ffmpeg eller bygg FFmpeg via NDK. Ta hänsyn till GPL/LGPL-licensbegränsningar vid kommersiell distribution.
Realtidsavkodning innebär att CPU:n kan avkoda bildrutor snabbare än de visas på skärmen (vanligtvis 30 eller 60 FPS). För 1080p H.264 klarar en modern mobil CPU detta med marginal, med omkring 30–50% av en produktiv kärna. För 4K H.265 i realtid på CPU är endast möjligt på flaggskepps-SoC:er med 70–90% belastning på alla kärnor.
Använd flertrådad avkodning (frame-level parallelism) via FFmpeg med flaggan thread_count, ställ in skip_frame på B-bildrutor (om acceptabelt för scenariot), minska upplösningen via scale-filtret före avkodning. För AV1 med dav1d, använd n_threads = antal CPU-kärnor minus ett.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också