FFmpeg视频处理入门级教程

news/2025/2/27 14:10:37

在这里插入图片描述

一、FFmpeg常规处理流程

初始化上下文
打开媒体文件
查找流信息
获取视频流索引
获取解码器
打开解码器
循环读取数据包
是否视频流?
解码数据包
处理解码帧
释放资源

文字说明:

  1. 初始化容器格式和编解码器
  2. 打开输入文件建立连接
  3. 解析媒体流信息(时长/分辨率/编码格式等)
  4. 遍历找到视频流索引
  5. 根据编码器ID查找对应解码器
  6. 初始化并配置解码器上下文
  7. 循环读取压缩数据包
  8. 判断数据包类型并解码视频帧
  9. 对原始帧进行格式转换或处理
  10. 释放所有分配的资源

二、FFmpeg核心模块解析

2.1 模块预览

FFmpeg由多个功能模块组成,以下是8个核心模块的详细说明:

模块名称功能描述典型应用场景
libavcodec编解码库,包含主流音视频编码器的实现H.264解码、MP3编码、音频重采样
libavformat封装/解封装库,处理多媒体容器格式(MP4/MKV/FLV等)解析MP4文件头信息、将H.264流封装为TS格式
libavutil基础工具库,提供通用数据结构、数学运算等基础功能时间戳计算、内存管理、日志输出
libswscale图像处理库,实现色彩空间转换和图像缩放YUV420转RGB24、4K视频缩放到1080p
libavfilter滤镜处理库,支持多路视频流的复杂滤镜处理添加水印、视频画中画、音频混音
libavdevice设备访问库,支持采集显示设备数据摄像头抓取画面、屏幕录制、音频采集卡输入
libswresample音频重采样库,处理音频格式转换48kHz转44.1kHz、单声道转立体声、PCM格式转换
libpostproc后处理库,提供视频后期效果处理视频去块效应、MPEG视频补偿

模块依赖关系:

avformat → avcodec → avutil
avfilter → avformat
swscale/swresample → avutil

2.2 部分模块说明详解:

libavcodec 工作机理

输入编码数据
解析帧头信息
初始化解码器
空间分配
熵解码
反量化
反变换
运动补偿
输出YUV帧

libavfilter 处理链示例

// 创建滤镜图:视频缩放+叠加水印
filter_graph = avfilter_graph_alloc();
avfilter_graph_create_filter(&buffer_src_ctx, "输入源");
avfilter_graph_create_filter(&scale_filter, "scale=640:480");
avfilter_graph_create_filter(&overlay_filter, "overlay=10:10");
avfilter_graph_create_filter(&buffer_sink_ctx, "输出端");

// 连接滤镜节点
avfilter_link(buffer_src_ctx, 0, scale_filter, 0);
avfilter_link(scale_filter, 0, overlay_filter, 0);
avfilter_link(overlay_filter, 0, buffer_sink_ctx, 0);

模块选择原则

  1. 文件操作:优先使用avformat
  2. 编解码处理:使用avcodec
  3. 图像处理:使用swscale或avfilter
  4. 实时流采集:配合avdevice使用

三、核心API函数说明

函数名称功能描述关键参数说明
av_register_all()注册所有封装格式与编解码器(新版本已弃用)无参数
avformat_open_input()打开媒体文件并初始化AVFormatContextps: 上下文指针地址
url: 文件路径
fmt: 强制指定格式(可NULL)
avformat_find_stream_info()获取媒体流详细信息ic: 上下文指针
options: 额外选项(通常NULL)
avcodec_find_decoder()根据编码ID查找解码器id: 编码格式ID(如AV_CODEC_ID_H264)
avcodec_open2()打开解码器avctx: 解码器上下文
codec: 解码器指针
options: 额外参数
av_read_frame()读取媒体文件中的数据包s: 上下文指针
pkt: 输出的数据包
avcodec_send_packet()发送压缩数据到解码器avctx: 解码器上下文
avpkt: 输入数据包
avcodec_receive_frame()从解码器获取解码后的帧avctx: 解码器上下文
frame: 输出的原始帧
sws_getContext()初始化图像缩放转换上下文参数包含源/目标分辨率、格式等图像特征
sws_scale()执行像素格式转换和缩放sws_ctx: 转换上下文
srcSlice: 源数据指针

四、视频解码显示实战

实现一个ffmpeg读取视频文件,并使用opencv进行显示的例子。

4.1 实现流程图

初始化FFmpeg
打开视频文件
获取视频流信息
定位视频流索引
配置解码器
初始化SWS转换上下文
循环读取帧
解码完成?
读取数据包
是视频包?
发送到解码器
接收解码帧
转换为RGB格式
OpenCV显示
释放资源

4.2 完整实现代码

#include <opencv2/opencv.hpp>
extern "C" {
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}

int main() {
    // 初始化FFmpeg
    avformat_network_init();
    AVFormatContext* fmt_ctx = NULL;
    
    // 打开输入文件
    if(avformat_open_input(&fmt_ctx, "test.mp4", NULL, NULL) != 0){
        printf("无法打开文件\n");
        return -1;
    }

    // 获取流信息
    if(avformat_find_stream_info(fmt_ctx, NULL) < 0){
        printf("无法获取流信息\n");
        return -1;
    }

    // 查找视频流索引
    int video_stream = -1;
    for(int i=0; i<fmt_ctx->nb_streams; i++){
        if(fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
            video_stream = i;
            break;
        }
    }

    // 获取解码器参数
    AVCodecParameters* codec_par = fmt_ctx->streams[video_stream]->codecpar;
    const AVCodec* decoder = avcodec_find_decoder(codec_par->codec_id);
    
    // 初始化解码器上下文
    AVCodecContext* codec_ctx = avcodec_alloc_context3(decoder);
    avcodec_parameters_to_context(codec_ctx, codec_par);
    avcodec_open2(codec_ctx, decoder, NULL);

    // 准备转换上下文(YUV->RGB)
    SwsContext* sws_ctx = sws_getContext(
        codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt,
        codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24,
        SWS_BILINEAR, NULL, NULL, NULL);

    // 准备帧结构
    AVFrame* frame = av_frame_alloc();
    AVFrame* rgb_frame = av_frame_alloc();
    uint8_t* buffer = (uint8_t*)av_malloc(av_image_get_buffer_size(
        AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1));
    av_image_fill_arrays(rgb_frame->data, rgb_frame->linesize, 
        buffer, AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1);

    AVPacket pkt;
    while(av_read_frame(fmt_ctx, &pkt) >= 0){
        if(pkt.stream_index == video_stream){
            // 发送到解码器
            avcodec_send_packet(codec_ctx, &pkt);
            
            // 接收解码帧
            while(avcodec_receive_frame(codec_ctx, frame) == 0){
                // 格式转换
                sws_scale(sws_ctx, 
                    (const uint8_t* const*)frame->data, frame->linesize,
                    0, codec_ctx->height,
                    rgb_frame->data, rgb_frame->linesize);

                // OpenCV显示
                cv::Mat img(codec_ctx->height, codec_ctx->width, 
                    CV_8UC3, rgb_frame->data[0]);
                cv::imshow("Video", img);
                cv::waitKey(1);
            }
        }
        av_packet_unref(&pkt);
    }

    // 释放资源
    av_frame_free(&frame);
    av_frame_free(&rgb_frame);
    avcodec_free_context(&codec_ctx);
    avformat_close_input(&fmt_ctx);
    sws_freeContext(sws_ctx);
    return 0;
}

4.3 关键代码解析

  1. 图像转换配置:
sws_ctx = sws_getContext(   // 创建转换器实例
    srcW, srcH, srcFormat,  // 源图像参数
    dstW, dstH, dstFormat,  // 目标图像参数
    flags,                  // 缩放算法选择
    ...);                   // 其他可选参数
  1. OpenCV显示核心:
cv::Mat img(height, width,        // 创建Mat对象
    CV_8UC3,                      // 数据类型:8位无符号3通道
    rgb_frame->data[0],           // RGB数据首地址
    rgb_frame->linesize[0]);      // 每行字节数(步长)
  1. 解码循环逻辑:
while(av_read_frame() >=0){       // 读取压缩包
    if(视频流){
        avcodec_send_packet();    // 送入解码队列
        while(avcodec_receive_frame() ==0){ // 获取解码帧
            // 处理帧数据
        }
    }
    av_packet_unref();            // 必须释放数据包
}

五、常见问题处理

  1. 颜色显示异常:检查像素格式转换参数(AV_PIX_FMT_RGB24)
  2. 无法打开文件:检查文件路径和FFmpeg的协议支持
  3. 内存泄漏:确保每个av_malloc都有对应的av_free
  4. 花屏现象:检查解码器是否成功初始化,数据包是否完整

http://www.niftyadmin.cn/n/5868693.html

相关文章

深入浅出ES6:现代JavaScript的基石

ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的一次重大更新&#xff0c;引入了许多新特性&#xff0c;使JavaScript更加强大、优雅和易于维护。这些特性已经成为现代JavaScript开发的基石&#xff0c;掌握它们对于任何JavaScript开发者都至关重要。本文将深入…

【Python模块】——pymysql

pymysql是python操作mysql的标准库&#xff0c;可以通过pip install快速导入pymysql包操作数据库 使用pymysql操作mysql 简单demo import pymysql connect pymysql.connect(host"localhost",port3306,user"root",password"root",database&quo…

ui设计公司兰亭妙微分享:科研单位UI界面设计

科研单位的UI界面设计是一项至关重要的任务&#xff0c;它不仅关乎科研工作的效率&#xff0c;还直接影响到科研人员的用户体验。以下是对科研单位UI界面设计的详细分析&#xff1a; 一、设计目标 科研单位的UI界面设计旨在提升科研工作的效率与便捷性&#xff0c;同时确保科…

2024最新版鸿蒙纯血原生应用开发教程文档丨学习ArkTS语言-基本语法

ArkTS是HarmonyOS的主要应用开发语言&#xff0c;在TypeScript基础上进行了扩展&#xff0c;保留了其基本风格&#xff0c;并通过增强静态检查和分析来提高程序的稳定性和性能。本教程将帮助开发者掌握ArkTS的核心功能、语法及最佳实践&#xff0c;以便高效地构建高性能移动应用…

1分钟用DeepSeek编写一个PDF转Word软件

一、引言 如今&#xff0c;在线工具的普及让PDF转Word成为了一个常见需求&#xff0c;常见的pdf转word工具有收费的wps&#xff0c;免费的有pdfgear&#xff0c;见下文&#xff1a; PDFgear:一款免费的PDF编辑、格式转化软件-CSDN博客 还有网上在线的免费pdf转word工具smallp…

B站pwn教程笔记-3

栈知识、部分保护措施 GDB显示的栈地址有时候并不是可靠的地址&#xff0c;gdb也是用特殊的进程映像来拿地址的。且gdb默认关闭栈地址随机化。但是&#xff0c;偏移量是没有错误的。目前还没学到咋解决 第一个栈帧是main函数栈帧&#xff0c;之前的一些系统函数什么的没有栈帧…

【Android】用 chrome://inspect/#devices 调试H5页面

通常做Android开发的过程中&#xff0c;不可避免的需要遇到去与H5交互&#xff0c;甚至有时候需要去调试H5的信息。 这里分享一下Android工程里如何调试H5页面信息&#xff1a; 直接在浏览器地址栏输入 &#xff1a; chrome://inspect/#devices 直接连接手机usb,打开开发者模式…

猿大师播放器:交通水利、公安消防Web端Vue网页播放20路RTSP H.265 1080P监控视频流

随着互联网技术的飞速发展&#xff0c;视频监控已成为各行各业不可或缺的一部分。无论是交通物流、公安消防&#xff0c;还是水利农业、园区校园&#xff0c;视频监控都扮演着至关重要的角色。然而&#xff0c;传统的视频监控解决方案往往依赖于特定的客户端软件&#xff0c;这…