Giải mã trong ứng dụng di động: khái niệm, kiến thức cơ bản và nguyên lý hoạt động

Tác giả: IT Sectr Đã đăng: 2026-05-25 Thời gian đọc: 10 phút

Giải mã là quá trình chuyển đổi luồng phương tiện nén sang định dạng không nén phù hợp để xuất ra màn hình và loa. Trong các thiết bị di động, giải mã được thực hiện qua phần mềm thông qua CPU hoặc qua phần cứng thông qua các khối GPU và DSP chuyên dụng. Theo MDN Web Docs (2026), các codec hiện đại nén luồng từ 100–500 lần và giải mã khôi phục chất lượng gốc không mất mát khi chọn đúng cấu hình nén.

Những điểm chính

  • Giải mã — chuyển đổi phương tiện nén sang định dạng PCM không nén để xuất ra thiết bị
  • Codec H.264, H.265, VP9 và AV1 sử dụng các thuật toán nén và cấu hình chất lượng khác nhau
  • Giải mã phần cứng được thực hiện trên GPU/DSP và tiêu thụ năng lượng ít hơn 3–5 lần so với phần mềm
  • Giải mã phần mềm qua FFmpeg đảm bảo tương thích với mọi định dạng nhưng gây tải CPU
  • Lựa chọn bộ giải mã ảnh hưởng đến thời gian phát lại, nhiệt độ thiết bị và thời lượng pin

Giải mã là gì?

Giải mã là quá trình chuyển đổi dữ liệu số nén trở lại định dạng không nén ban đầu. Trong bối cảnh phương tiện, giải mã khôi phục các khung hình video từ luồng bit nén được tạo bởi bộ mã hóa. Nếu không có giải mã, người dùng không thể xem video hoặc nghe âm thanh vì tất cả các định dạng phương tiện hiện đại đều sử dụng nén để tiết kiệm băng thông và dung lượng đĩa.

Một luồng video điển hình ở định dạng H.264 với tốc độ bit 5 Mbps chiếm dung lượng ít hơn 100 lần so với luồng RGB không nén có cùng độ phân giải. Thuật toán giải mã phải khôi phục từng khung hình về độ phân giải và không gian màu gốc, tuân theo thông số kỹ thuật của codec theo thứ tự ngược lại so với mã hóa. Để làm điều này, bộ giải mã xử lý dữ liệu nội khung (I-frame) và liên khung (P-frame, B-frame).

Trên thiết bị di động, giải mã có thể diễn ra trên CPU hoặc trên các khối phần cứng chuyên dụng. Các SoC hiện đại từ Apple (dòng A), Qualcomm (Snapdragon) và MediaTek (Dimensity) đều có bộ giải mã tích hợp cho mọi định dạng phổ biến. Bộ xử lý video đảm nhận công việc nặng về biến đổi cosin rời rạc ngược và bù chuyển động, giải phóng CPU cho các tác vụ khác.

Giải mã hoạt động như thế nào?

Quá trình giải mã bao gồm nhiều giai đoạn tuần tự đảo ngược các bước mã hóa. Đầu tiên, các tiêu đề và tham số nén — cấu hình, mức, độ phân giải, không gian màu — được trích xuất từ luồng bit. Sau đó, bộ giải mã xử lý tuần tự các macroblock nén, áp dụng các biến đổi ngược cho chúng.

Các giai đoạn giải mã luồng video

Giai đoạn đầu tiên là trích xuất mã entropy. Giải mã entropy sử dụng thuật toán CABAC hoặc CAVLC để khôi phục các hệ số biến đổi cosin rời rạc. Giai đoạn này không phụ thuộc vào độ phân giải video — nó xử lý luồng bit chứ không phải pixel, và độ phức tạp được xác định bởi tốc độ bit, không phải kích thước khung hình.

Giai đoạn thứ hai là lượng tử hóa ngược và DCT ngược. Bộ giải mã nhân các hệ số đã lượng tử hóa với bước lượng tử, khôi phục giá trị hệ số DCT gần đúng, sau đó áp dụng biến đổi DCT ngược. DCT ngược khôi phục dữ liệu không gian từ miền tần số, tạo thành một macroblock pixel. Biến đổi được thực hiện độc lập cho chroma và luma.

Giai đoạn thứ ba là bù chuyển động. Đối với khung P và B, bộ giải mã sử dụng vector chuyển động được trích xuất từ luồng bit và tham chiếu đến các khung tham chiếu đã được giải mã trước đó. Bù chuyển động tạo ra một bộ dự đoán cho macroblock hiện tại, được cộng với tín hiệu dư sau DCT ngược. Kết quả là một khung hình được khôi phục hoàn toàn sẵn sàng để xuất ra.

cpp
// Mã giả cơ bản của giải mã khung hình video
struct DecodedFrame {
    uint8_t* y_plane;
    uint8_t* u_plane;
    uint8_t* v_plane;
    int width, height;
};

class Decoder {
public:
    bool decodeNALUnit(const uint8_t* nalUnit, size_t size) {
        if (!parseNALUHeader(nalUnit, size))
            return false;
        
        int sliceType = parseSliceType(nalUnit);
        entropyDecode(nalUnit);
        inverseQuantize();
        inverseDCT();
        
        if (sliceType != I_SLICE)
            motionCompensation();
        
        return true;
    }
};

Ví dụ trên cho thấy cấu trúc cơ bản của bộ giải mã H.264. Hàm decodeNALUnit nhận một đơn vị NAL — khối cơ bản của luồng H.264 nén. Bộ giải mã phân tích tuần tự tiêu đề, trích xuất loại slice, áp dụng giải mã entropy, lượng tử hóa ngược và DCT ngược. Đối với slice P và B, bù chuyển động được thực hiện thêm bằng cách sử dụng các khung tham chiếu từ bộ đệm DPB.

Định dạng nén và codec

Các codec video hiện đại khác nhau về thuật toán nén, hiệu quả và yêu cầu tài nguyên tính toán. Lựa chọn định dạng ảnh hưởng trực tiếp đến kích thước tệp, chất lượng hình ảnh và mức tiêu thụ điện năng khi giải mã trên thiết bị di động.

CodecNămNénHỗ trợ phần cứng
H.26420031:100Tất cả SoC hiện đại
H.26520131:200Apple A8+, Snapdragon 805+
VP920131:180Snapdragon 820+, Exynos
AV120181:300Apple A17+, Snapdragon 8 Gen 2+

H.264 là codec video phổ biến nhất, được hỗ trợ bởi tất cả thiết bị di động. Ưu điểm chính của nó là tính phổ quát: mọi điện thoại thông minh Android và iPhone đều có thể giải mã H.264 bằng phần cứng. Tuy nhiên, ở cùng tốc độ bit, H.264 kém chất lượng hơn so với các codec hiện đại như H.265 và AV1, yêu cầu tốc độ bit cao hơn 30–50% để có chất lượng hình ảnh tương tự.

H.265 cung cấp khả năng nén gấp đôi so với H.264 ở cùng chất lượng. Giải mã H.265 yêu cầu khối phần cứng mạnh hơn: VideoToolbox trên iOS hỗ trợ H.265 từ iPhone 6 (A8), và thiết bị Android từ Snapdragon 805 trở lên. Khi chọn H.265 cho ứng dụng di động, cần lưu ý rằng thiết bị cũ có thể không có hỗ trợ phần cứng và sẽ giải mã định dạng này bằng phần mềm, làm tăng mạnh mức tiêu thụ điện năng.

AV1 là codec mở từ Alliance for Open Media, cung cấp khả năng nén tốt nhất trong số tất cả các định dạng hiện đại. AV1 hiệu quả hơn 30% so với H.265 và 50% so với H.264 ở cùng chất lượng hình ảnh. Giải mã AV1 bằng phần cứng chỉ xuất hiện trong các SoC từ năm 2023+: Apple A17 Pro, Qualcomm Snapdragon 8 Gen 2 và mới hơn. Đối với thiết bị cũ, giải mã AV1 chỉ khả thi bằng phần mềm qua thư viện dav1d, tạo ra tải đáng kể lên CPU.

Giải mã phần mềm so với phần cứng

Lựa chọn giữa giải mã phần mềm và phần cứng là quyết định kiến trúc quan trọng khi phát triển trình phát phương tiện di động. Mỗi cách tiếp cận đều có ưu điểm và hạn chế cần được xem xét khi thiết kế ứng dụng.

Hiệu suất và mức tiêu thụ điện năng

Giải mã phần cứng được thực hiện trên các khối xử lý video chuyên dụng tiêu thụ ít năng lượng hơn đáng kể so với CPU khi thực hiện cùng một tác vụ. Theo Qualcomm, bộ giải mã H.265 phần cứng tiêu thụ năng lượng ít hơn 5–10 lần so với giải mã phần mềm trên CPU Snapdragon 8 Gen 1 khi phát video 4K. Điều này rất quan trọng đối với thiết bị di động, nơi mỗi miliwatt đều ảnh hưởng đến thời lượng pin.

Mặt khác, giải mã phần mềm mang lại sự linh hoạt tối đa. FFmpeg với thư viện libavcodec hỗ trợ hàng chục codec và container, bao gồm các định dạng hiếm và lỗi thời không có hỗ trợ phần cứng. Nhà phát triển có thể sửa đổi quy trình giải mã, thêm xử lý hậu kỳ và bộ lọc ngay lập tức, điều không thể khi sử dụng các khối phần cứng đóng.

Khi nào nên chọn giải mã phần mềm

Giải mã phần mềm phù hợp trong một số tình huống: khi phát các định dạng hiếm (ProRes, DNxHD, Motion JPEG), khi cần kiểm soát chính xác từng giai đoạn xử lý khung hình và khi giải mã AV1 trên thiết bị không có hỗ trợ phần cứng. libavcodec từ FFmpeg có thể giải mã hầu như mọi định dạng đã biết, khiến nó trở thành tiêu chuẩn thực tế cho các trình phát phương tiện đa năng.

Hạn chế của giải mã phần mềm là tản nhiệt. Giải mã video 4K liên tục trên CPU có thể làm nóng thiết bị lên 45–50 độ trong vòng 10–15 phút, dẫn đến giảm tốc và giảm tốc độ khung hình. Trên thiết bị không có làm mát chủ động (máy tính bảng, điện thoại), điều này đặc biệt đáng chú ý. Mức tiêu thụ điện năng CPU khi giải mã phần mềm có thể đạt 3–5 W so với 0,3–0,5 W khi giải mã phần cứng cùng một luồng.

Khi nào nên chọn giải mã phần cứng

Giải mã phần cứng là lựa chọn mặc định cho bất kỳ trình phát phương tiện sản xuất nào. Nó cung cấp 60 khung hình/giây ổn định cho video 4K với mức tiêu thụ điện năng tối thiểu. VideoToolbox trên iOS và MediaCodec trên Android cung cấp API gốc cho giải mã phần cứng tự động chọn khối xử lý tối ưu tùy theo codec và độ phân giải.

API nền tảng quản lý bộ đệm khung hình (surface pool trên Android, CVPixelBufferPool trên iOS), đồng bộ hóa màn hình và tối ưu hóa bộ nhớ. Nhà phát triển chỉ cần mở bộ giải mã với các tham số yêu cầu và nhận khung hình đã sẵn sàng. Giải mã phần cứng hỗ trợ quy trình đầu cuối với độ trễ tối thiểu: từ khi nhận luồng bit đến hiển thị trên màn hình mất 5–15 ms so với 30–80 ms ở giải mã phần mềm.

Ví dụ mã giải mã

Hãy xem xét triển khai thực tế của giải mã trên cả hai nền tảng di động. Trên iOS, giải mã phần cứng được thực hiện qua VideoToolbox và giải mã phần mềm qua FFmpeg. Trên Android, MediaCodec được sử dụng cho giải mã phần cứng.

Giải mã phần cứng trên iOS với VideoToolbox

objective-c
@interface VideoDecoder ()
@property (nonatomic) VTDecompressionSessionRef session;
@end

@implementation VideoDecoder

- (void)setupDecoder {
    CMVideoFormatDescriptionRef formatDesc;
    CMVideoCodecType codecType = kCMVideoCodecType_H264;
    
    OSStatus status = CMVideoFormatDescriptionCreate(
        NULL, codecType, 1920, 1080, NULL, &formatDesc
    );
    
    VTDecompressionOutputCallbackRecord callback;
    callback.decompressionOutputCallback = &decodingCallback;
    
    VTDecompressionSessionCreate(NULL, formatDesc, NULL,
        NULL, &callback, &_session);
}

- (void)decodeFrame: (uint8_t*)nalData length:(size_t)size {
    CMBlockBufferRef blockBuffer;
    CMBlockBufferCreateWithMemoryBlock(NULL, nalData,
        size, NULL, NULL, 0, size, 0, &blockBuffer);
    
    CMSampleBufferRef sampleBuffer;
    CMSampleBufferCreate(NULL, blockBuffer, true, NULL,
        NULL, NULL, 1, 0, NULL, 0, NULL, &sampleBuffer);
    
    VTDecompressionSessionDecodeFrame(_session,
        sampleBuffer, 0, NULL, 0);
}

@end

Mã này minh họa việc khởi tạo bộ giải mã H.264 phần cứng trên iOS. VTDecompressionSessionCreate tạo phiên giải mã và VTCreate gọi callback khi có khung hình sẵn sàng. Phiên tự động sử dụng khối phần cứng nếu có sẵn cho codec được chỉ định. Để lấy khung hình đã giải mã ở định dạng CVPixelBuffer, một callback được sử dụng để truyền từng khung hình sẵn sàng với độ trễ tối thiểu.

Giải mã phần cứng trên Android với MediaCodec

java
MediaCodec decoder = MediaCodec.createDecoderByType("video/avc");
MediaFormat format = MediaFormat.createVideoFormat(
    "video/avc", 1920, 1080
);
format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);

decoder.configure(format, surface, null, 0);
decoder.start();

ByteBuffer[] inputBuffers = decoder.getInputBuffers();
int inputIndex = decoder.dequeueInputBuffer(10000);

if (inputIndex >= 0) {
    ByteBuffer buffer = inputBuffers[inputIndex];
    buffer.clear();
    buffer.put(nalData);
    decoder.queueInputBuffer(inputIndex, 0, nalData.length, pts, 0);
}

Trên Android, MediaCodec sử dụng Surface để xuất ra thay vì bộ đệm pixel, giảm thiểu việc sao chép dữ liệu giữa GPU và CPU. Bộ giải mã tự động chọn khối phần cứng (thành phần OMX) dựa trên loại codec. Đối với H.264, OMX.google.h264.decoder được sử dụng, có thể là phần cứng hoặc phần mềm tùy thuộc vào triển khai của nhà sản xuất.

Cách chọn bộ giải mã cho ứng dụng di động

Lựa chọn chiến lược giải mã phụ thuộc vào đối tượng mục tiêu của ứng dụng, định dạng được hỗ trợ và yêu cầu hiệu suất. Giải pháp tối ưu thường bao gồm cách tiếp cận kết hợp: giải mã phần cứng cho các định dạng chính (H.264, H.265) với dự phòng phần mềm cho codec hiếm.

Chiến lược lựa chọn theo ưu tiên

Nếu ứng dụng hướng đến khả năng tương thích tối đa — hãy sử dụng H.264, được đảm bảo giải mã bằng phần cứng trên mọi thiết bị. Đối với dịch vụ phát trực tuyến video, H.265 với hỗ trợ phần cứng trên thiết bị sau năm 2016 là phù hợp. AV1 là lựa chọn cho các dịch vụ mà việc tiết kiệm băng thông quan trọng: YouTube, Netflix và các nền tảng lớn khác đang tích cực áp dụng AV1 để giảm chi phí CDN trong khi vẫn duy trì chất lượng.

Một tham số quan trọng là kích thước bộ đệm của bộ giải mã. Bộ giải mã phần cứng có bộ đệm cố định (thường 4–16 khung hình). Khi phát luồng có tốc độ bit cao, bộ đệm có thể bị tràn, dẫn đến mất khung hình. MediaCodec cung cấp phương thức getOutputFrameRate để xác định hiệu suất thực tế của bộ giải mã trên thiết bị cụ thể, trong khi VideoToolbox cho phép kiểm soát ưu tiên thời gian thực qua kVTDecodeFrame_EnableAsynchronousDecompression.

Giảm tốc nhiệt là một yếu tố khác. Ngay cả giải mã phần cứng cũng có thể làm nóng thiết bị khi phát video 4K HDR kéo dài. Nên theo dõi nhiệt độ qua ProcessInfo trên iOS và BatteryManager trên Android, giảm chất lượng hoặc độ phân giải luồng khi quá nhiệt. Điều này đặc biệt quan trọng đối với trò chơi và ứng dụng phát trực tuyến có phiên xem dài.

Câu hỏi thường gặp

Giải mã khác mã hóa như thế nào?

Mã hóa chuyển đổi dữ liệu không nén thành định dạng nén, trong khi giải mã khôi phục dữ liệu gốc từ luồng nén. Hai quá trình này là ngược chiều nhau và sử dụng cùng thuật toán: DCT, lượng tử hóa, bù chuyển động. Bộ mã hóa thực hiện biến đổi thuận, bộ giải mã thực hiện biến đổi ngược.

Codec nào tốt nhất cho ứng dụng di động?

Để tương thích tối đa — H.264, vì nó được giải mã phần cứng trên 100% thiết bị hiện đại. Để nén tốt hơn — H.265 hoặc AV1. Lựa chọn phụ thuộc vào đối tượng: nếu 80% người dùng có thiết bị từ 2021+, H.265 sẽ cung cấp chất lượng tốt hơn với tốc độ bit thấp hơn. AV1 phù hợp cho thiết bị cao cấp có hỗ trợ phần cứng từ 2023+.

Tại sao giải mã phần cứng nhanh hơn giải mã phần mềm?

Bộ giải mã phần cứng là một vi mạch chuyên dụng (ASIC) được thiết kế riêng cho giải mã. Không giống CPU thực hiện giải mã bằng các lệnh tuần tự, khối phần cứng xử lý macroblock song song. Mức tiêu thụ điện năng của bộ giải mã phần cứng thấp hơn 5–10 lần vì chip hoạt động ở tần số thấp hơn và không có các giai đoạn pipeline không cần thiết.

Cấu hình và mức trong H.264 là gì?

Cấu hình (profile) xác định bộ thuật toán nén được sử dụng bởi bộ mã hóa: Baseline, Main, High. Mức (level) đặt các tham số tối đa của luồng: độ phân giải, tốc độ bit, kích thước bộ đệm. Đối với thiết bị di động, cấu hình High và mức 4.1–5.2 được khuyến nghị — đủ cho video 1080p–4K với giải mã phần cứng.

Làm thế nào để kiểm tra hỗ trợ codec trên thiết bị?

Trên Android, sử dụng MediaCodecList để lấy danh sách codec khả dụng và kiểm tra codec nào là phần cứng. Trên iOS, kiểm tra hỗ trợ qua CMVideoFormatDescription với codec được chỉ định — nếu VTDecompressionSessionCreate thành công, codec được hỗ trợ. Đối với AV1 trên Android, kiểm tra sự tồn tại của codec OMX.google.aomc.decoder hoặc phiên bản phần cứng của nó.

Tổng kết

  • Giải mã — quy trình ngược của mã hóa: từ luồng bit nén khôi phục khung hình video không nén gốc
  • Giải mã phần cứng chạy trên khối GPU/DSP, tiêu thụ năng lượng ít hơn 5–10 lần, nhưng bị giới hạn với các định dạng được hỗ trợ
  • Giải mã phần mềm qua FFmpeg/libavcodec cung cấp tương thích với mọi codec nhưng tải CPU và gây nóng
  • H.264 — codec phổ quát với hỗ trợ phần cứng trên mọi thiết bị, tối ưu cho tương thích tối đa
  • H.265 cung cấp khả năng nén gấp đôi, hỗ trợ phần cứng trên thiết bị sau 2016
  • AV1 — codec hiệu quả nhất với hỗ trợ phần cứng trên thiết bị cao cấp từ 2023+ và phần mềm qua dav1d trên thiết bị cũ
  • Chọn chiến lược kết hợp: giải mã phần cứng cho định dạng chính với dự phòng phần mềm cho codec hiếm

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm