FFmpeg教程:libswscale对图像进行简单处理

我们在FFmpeg简单总结对FFmpeg 组成模块,编码进行了简单介绍。

FFmpeg组成部分:

libavcodec: 提供了音视频编解码器的库。

libavformat: 处理多媒体容器格式的库,包括封装和解封装。

libavutil: 包含一些公共的实用工具函数。

libswscale: 提供图像缩放和颜色转换功能的库。

libavfilter: 实现音视频过滤器的库,用于进行各种音视频处理操作。

ffmpeg: 命令行工具,用于进行音视频处理和转码。

ffprobe: 用于检测多媒体文件信息的命令行工具。

ffplay: 简单的播放器,支持音视频播放。

libswscale

libswscale(Software Scaling and Conversion Library)是FFmpeg中的一个库,用于执行图像缩放、颜色空间转换以及图像格式转换等操作。它主要提供了一些函数和工具,使得在视频处理过程中可以方便地进行图像大小和颜色空间的调整。

常用的API介绍

sws_getContext: 创建并返回一个SwsContext对象,用于设置缩放和颜色空间转换的参数。

c 复制代码
struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat,
                                  int dstW, int dstH, enum AVPixelFormat dstFormat,
                                  int flags, SwsFilter *srcFilter,
                                  SwsFilter *dstFilter, const double *param);

sws_scale: 将输入图像进行缩放和颜色空间转换,并将结果输出到目标图像。

c 复制代码
int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[],
              const int srcStride[], int srcSliceY, int srcSliceH,
              uint8_t *const dst[], const int dstStride[]);

sws_freeContext: 释放SwsContext对象占用的资源。

c 复制代码
void sws_freeContext(struct SwsContext *swsContext);

灰度化

下面给出一个例子,使用FFmpeg对图像进行处理,该程序解码视频流,选取视频流中的输入图片,进行灰度化处理,然后保存为新的图片

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

void process_image(const char *input_filename, const char *output_filename) {
    AVFormatContext *input_format_context = NULL;
    AVCodecContext *codec_context = NULL;
    AVCodec *codec = NULL;
    AVFrame *frame = NULL;
    AVFrame *gray_frame = NULL;
    AVPacket packet;
    struct SwsContext *sws_context = NULL;

    // Register FFmpeg components
    av_register_all();

    // Open input file
    if (avformat_open_input(&input_format_context, input_filename, NULL, NULL) != 0) {
        fprintf(stderr, "Error opening input file\n");
        exit(EXIT_FAILURE);
    }

    // Retrieve stream information
    if (avformat_find_stream_info(input_format_context, NULL) < 0) {
        fprintf(stderr, "Error finding stream information\n");
        exit(EXIT_FAILURE);
    }

    // Find the first video stream
    int video_stream_index = -1;
    for (int i = 0; i < input_format_context->nb_streams; i++) {
        if (input_format_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_stream_index = i;
            break;
        }
    }

    if (video_stream_index == -1) {
        fprintf(stderr, "Error: No video stream found\n");
        exit(EXIT_FAILURE);
    }

    // Find the decoder for the video stream
    codec = avcodec_find_decoder(input_format_context->streams[video_stream_index]->codecpar->codec_id);
    if (!codec) {
        fprintf(stderr, "Error: No decoder found\n");
        exit(EXIT_FAILURE);
    }

    // Allocate a codec context for the decoder
    codec_context = avcodec_alloc_context3(codec);
    if (!codec_context) {
        fprintf(stderr, "Error allocating codec context\n");
        exit(EXIT_FAILURE);
    }

    // Copy codec parameters from input stream to codec context
    if (avcodec_parameters_to_context(codec_context, input_format_context->streams[video_stream_index]->codecpar) < 0) {
        fprintf(stderr, "Error setting codec parameters\n");
        exit(EXIT_FAILURE);
    }

    // Open codec
    if (avcodec_open2(codec_context, codec, NULL) < 0) {
        fprintf(stderr, "Error opening codec\n");
        exit(EXIT_FAILURE);
    }

    // Allocate video frames
    frame = av_frame_alloc();
    gray_frame = av_frame_alloc();
    if (!frame || !gray_frame) {
        fprintf(stderr, "Error allocating frames\n");
        exit(EXIT_FAILURE);
    }

    // Determine required buffer size and allocate buffer
    int num_bytes = av_image_get_buffer_size(AV_PIX_FMT_GRAY8, codec_context->width, codec_context->height, 1);
    uint8_t *buffer = (uint8_t *)av_malloc(num_bytes * sizeof(uint8_t));

    // Assign appropriate parts of buffer to image planes in gray_frame
    av_image_fill_arrays(gray_frame->data, gray_frame->linesize, buffer, AV_PIX_FMT_GRAY8, codec_context->width, codec_context->height, 1);

    // Initialize SwsContext for converting between color spaces
    sws_context = sws_getContext(
        codec_context->width, codec_context->height, codec_context->pix_fmt,
        codec_context->width, codec_context->height, AV_PIX_FMT_GRAY8,
        SWS_BILINEAR, NULL, NULL, NULL);

    // Open output file
    FILE *output_file = fopen(output_filename, "wb");
    if (!output_file) {
        fprintf(stderr, "Error opening output file\n");
        exit(EXIT_FAILURE);
    }

    // Read frames from the input file, convert to grayscale, and write to the output file
    while (av_read_frame(input_format_context, &packet) == 0) {
        if (packet.stream_index == video_stream_index) {
            // Decode video frame
            if (avcodec_receive_frame(codec_context, frame) == 0) {
                // Convert frame to grayscale
                sws_scale(sws_context, frame->data, frame->linesize, 0, frame->height, gray_frame->data, gray_frame->linesize);

                // Write grayscale frame to output file
                fwrite(gray_frame->data[0], 1, num_bytes, output_file);
            }
        }

        av_packet_unref(&packet);
    }

    // Cleanup
    fclose(output_file);
    av_frame_free(&frame);
    av_frame_free(&gray_frame);
    av_free(buffer);
    sws_freeContext(sws_context);
    avcodec_close(codec_context);
    avformat_close_input(&input_format_context);
}

int main() {
    const char *input_filename = "input.jpg";
    const char *output_filename = "output.gray";
    process_image(input_filename, output_filename);
    return 0;
}

放大缩小

也可以直接用接口函数,对image操作

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libswscale/swscale.h>

int main() {
    // Input image parameters
    int src_width = 1920;
    int src_height = 1080;
    enum AVPixelFormat src_format = AV_PIX_FMT_RGB24;

    // Output image parameters
    int dst_width = 640;
    int dst_height = 360;
    enum AVPixelFormat dst_format = AV_PIX_FMT_YUV420P;

    // Allocate source and destination buffers
    uint8_t *src_data[4];
    int src_linesize[4];
    uint8_t *dst_data[4];
    int dst_linesize[4];

    // Initialize SwsContext
    struct SwsContext *sws_context = sws_getContext(src_width, src_height, src_format,
                                                    dst_width, dst_height, dst_format,
                                                    SWS_BILINEAR, NULL, NULL, NULL);

    // Perform scaling and color space conversion
    sws_scale(sws_context, src_data, src_linesize, 0, src_height,
              dst_data, dst_linesize);

    // Free resources
    sws_freeContext(sws_context);

    return 0;
}
相关推荐
winfredzhang1 天前
实战:从零构建一个支持屏幕录制与片段合并的视频管理系统 (Node.js + FFmpeg)
ffmpeg·node.js·音视频·录屏
winfredzhang1 天前
自动化视频制作:深入解析 FFmpeg 图片转视频脚本
ffmpeg·自动化·音视频·命令行·bat·图片2视频
胖_大海_2 天前
【FFmpeg+Surface 底层渲染,实现超低延迟100ms】
ffmpeg
冷冷的菜哥2 天前
springboot调用ffmpeg实现对视频的截图,截取与水印
java·spring boot·ffmpeg·音视频·水印·截图·截取
进击的CJR3 天前
redis哨兵实现主从自动切换
mysql·ffmpeg·dba
huahualaly3 天前
重建oracle测试库步骤
数据库·oracle·ffmpeg
aqi003 天前
FFmpeg开发笔记(九十九)基于Kotlin的国产开源播放器DKVideoPlayer
android·ffmpeg·kotlin·音视频·直播·流媒体
lizongyao3 天前
FFMPEG命令行典型案例
ffmpeg
冷冷的菜哥3 天前
ASP.NET Core调用ffmpeg对视频进行截图,截取,增加水印
开发语言·后端·ffmpeg·asp.net·音视频·asp.net core
冷冷的菜哥3 天前
go(golang)调用ffmpeg对视频进行截图、截取、增加水印
后端·golang·ffmpeg·go·音视频·水印截取截图