完全可以,且是工業界主流選擇。 FFmpeg、x264/x265、VLC、OBS、GStreamer、Chrome/FFmpeg、Android MediaCodec 底層、iOS VideoToolbox 封裝,**核心均為 C/C++**。
| 層級 | 典型庫/框架 | 語言 | 核心能力 |
|---|---|---|---|
| 容器/協議 | FFmpeg (libavformat), libmp4v2, MKVToolNix | C | 封裝/解封裝、流協議 (RTMP/HLS/SRT/RIST) |
| 編解碼 | FFmpeg (libavcodec), x264/x265, libvpx, dav1d, SVT-AV1 | C/C++ | H.264/H.265/VP9/AV1 硬軟編解碼 |
| 濾鏡/處理 | FFmpeg (libavfilter), OpenCV, libplacebo | C/C++ | 縮放/色彩空間/去隔行/字幕燒錄/特效 |
| 設備輸入 | V4L2 (Linux), DirectShow/MediaFoundation (Windows), AVFoundation (macOS/iOS), Camera2 (Android) | C/C++/ObjC/Java | 攝像頭/捕獲卡/桌面錄製/虛擬設備 |
| 渲染輸出 | SDL2, OpenGL/Vulkan/Metal/DirectX11/12, libplacebo | C/C++ | 零拷貝渲染、HDR/色彩管理、VR/AR |
| 應用框架 | GStreamer, Qt Multimedia, Chromium Mojo, Electron | C/C++/Rust/JS | 管道編排、同步時鐘、元數據、插件架構 |
// 簡化版:僅展示核心流程,完整代碼見 ffplay.c
#include
#include
#include
#include
int main(int argc, char* argv[]) {
avformat_network_init();
AVFormatContext* fmt_ctx = NULL;
avformat_open_input(&fmt_ctx, argv[1], NULL, NULL);
avformat_find_stream_info(fmt_ctx, NULL);
int video_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
AVCodecContext* dec_ctx = avcodec_alloc_context3(NULL);
avcodec_parameters_to_context(dec_ctx, fmt_ctx->streams[video_idx]->codecpar);
avcodec_open2(dec_ctx, avcodec_find_decoder(dec_ctx->codec_id), NULL);
SDL_Window* win = SDL_CreateWindow("Player", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
dec_ctx->width, dec_ctx->height, SDL_WINDOW_RESIZABLE);
SDL_Renderer* ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
SDL_Texture* tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,
dec_ctx->width, dec_ctx->height);
AVPacket* pkt = av_packet_alloc();
AVFrame* frame = av_frame_alloc();
AVFrame* yuv = av_frame_alloc();
uint8_t* yuv_buf = av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, dec_ctx->width, dec_ctx->height, 1));
av_image_fill_arrays(yuv->data, yuv->linesize, yuv_buf, AV_PIX_FMT_YUV420P, dec_ctx->width, dec_ctx->height, 1);
struct SwsContext* sws = sws_getContext(dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
dec_ctx->width, dec_ctx->height, AV_PIX_FMT_YUV420P,
SWS_BILINEAR, NULL, NULL, NULL);
while (av_read_frame(fmt_ctx, pkt) >= 0) {
if (pkt->stream_index == video_idx) {
avcodec_send_packet(dec_ctx, pkt);
while (avcodec_receive_frame(dec_ctx, frame) == 0) {
sws_scale(sws, frame->data, frame->linesize, 0, dec_ctx->height, yuv->data, yuv->linesize);
SDL_UpdateYUVTexture(tex, NULL, yuv->data[0], yuv->linesize[0],
yuv->data[1], yuv->linesize[1], yuv->data[2], yuv->linesize[2]);
SDL_RenderClear(ren); SDL_RenderCopy(ren, tex, NULL, NULL); SDL_RenderPresent(ren);
}
}
av_packet_unref(pkt);
SDL_Event e; while (SDL_PollEvent(&e)) if (e.type == SDL_QUIT) goto cleanup;
}
cleanup:
// 釋放所有資源...
return 0;
}
doc/examples 目錄下示例代碼 (ffplay.c, transcoding.c, filtering.c);