【FFMpeg SDK使用】8、调用FFmpeg SDK实现视频缩放

  • 视频缩放:视频内容不变,通过对视频的像素数据进行采样或插值,将画面的分辨率从一种尺寸变换到另一种尺寸。包括低清晰度到高清晰度或者高清晰度到低清晰度
  • 视频缩放是视频基本操作之一,可以使视频内容更加适应显示设备的尺寸,提升观看者的体验效果
  • libswscale:FFMPEG库,实现视频缩放、颜色空间转换等功能
  • swscale操作的对象:视频滤镜针对像素域进行操作,即AVFrame中包含的信息。如果视频以码流的形式保存,则需要先进行解码生成AVFrame
  • 处理步骤:
    在这里插入图片描述
    通常情况下视频缩放的主要思想是对视频进行解码到像素域后,针对像素域的像素值进行采样或差值操作。这种方式需要在解码端消耗一定时间,但是通用性最好,不需要对码流格式作出任何特殊处理。在FFMpeg中libswscale库也是针对AVFrame结构进行缩放处理。

0、整体框图

在这里插入图片描述

1. 解析命令行参数

输入输出的数据使用以下结构进行封装:

typedef struct _IOFiles
{
    char *inputName;            //输入文件名
    char *outputName;           //输出文件名
    char *inputFrameSize;       //输入图像的尺寸
    char *outputFrameSize;      //输出图像的尺寸

    FILE *iFile;                //输入文件指针
    FILE *oFile;                //输出文件指针

} IOFiles;

输入参数解析过程为:

static bool hello(int argc, char **argv, IOFiles &files)
{
    printf("FFMpeg Scaling Demo.\nCommand format: %s input_file input_frame_size output_file output_frame_size\n", argv[0]);
    if (argc != 5)
    {
        printf("Error: command line error, please re-check.\n");
        return false;
    }

    files.inputName = argv[1];
    files.inputFrameSize = argv[2];
    files.outputName = argv[3];
    files.outputFrameSize = argv[4];

    fopen_s(&files.iFile, files.inputName, "rb+");
    if (!files.iFile)
    {
        printf("Error: cannot open input file.\n");
        return false;
    }

    fopen_s(&files.oFile, files.outputName, "wb+");
    if (!files.oFile)
    {
        printf("Error: cannot open output file.\n");
        return false;
    }

    return true;
}

在参数读入完成后,需要从表示视频分辨率的字符串中解析出图像的宽和高两个值。我们在命令行中传入的视频分辨率字符串的格式为“width x height”,例如”720x480”。解析过程需要调用av_parse_video_size函数。声明如下:

int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str);

例如,我们传入下面的参数:

int frameWidth, frameHeight;
av_parse_video_size(&frameWidth, &frameHeight, "720x480");

函数将分别把720和480传入frameWidth和frameHeight中。

在获取命令行参数后,调用该函数解析图像分辨率:

int srcWidth, srcHeight, dstWidth, dstHeight;
if (av_parse_video_size(&srcWidth, &srcHeight, files.inputFrameSize))
{
    printf("Error: parsing input size failed.\n");
    goto end;
}
if (av_parse_video_size(&dstWidth, &dstHeight, files.outputFrameSize))
{
    printf("Error: parsing output size failed.\n");
    goto end;
}

这样,我们就获得了源和目标图像的宽和高度。

2. 创建SwsContext结构

进行视频的缩放操作离不开libswscale的一个关键的结构,即SwsContext,该结构提供了缩放操作的必要参数。创建该结构需调用函数sws_getContext。该函数的声明如下:

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);

该函数的前两行参数分别表示输入和输出图像的宽、高、像素格式,参数flags表示采样和差值使用的算法,常用的有SWS_BILINEAR表示双线性差值等。剩余的不常用参数通常设为NULL。创建该结构的代码如:

//创建SwsContext结构
enum AVPixelFormat src_pix_fmt = AV_PIX_FMT_YUV420P;
enum AVPixelFormat dst_pix_fmt = AV_PIX_FMT_YUV420P;
struct SwsContext *sws_ctx = sws_getContext(srcWidth, srcHeight, src_pix_fmt, dstWidth, dstHeight, dst_pix_fmt, SWS_BILINEAR, NULL,NULL,NULL );
if (!sws_ctx)
{
    printf("Error: parsing output size failed.\n");
    goto end;
}

3. 分配像素缓存

视频缩放实际上是在像素域实现,但是实际上我们没有必要真的建立一个个AVFrame对象,我们只需要其像素缓存空间即可,我们定义两个指针数组和两个保存stride的数组,并为其分配内存区域:
//分配input和output
uint8_t *src_data[4], *dst_data[4];
int src_linesize[4], dst_linesize[4];
if ((ret = av_image_alloc(src_data, src_linesize, srcWidth, srcHeight, src_pix_fmt, 32)) < 0)
{
printf(“Error: allocating src image failed.\n”);
goto end;
}
if ((ret = av_image_alloc(dst_data, dst_linesize, dstWidth, dstHeight, dst_pix_fmt, 1)) < 0)
{
printf(“Error: allocating dst image failed.\n”);
goto end;
}

4.循环处理输入frame

循环处理的代码为:

//从输出frame中写出到输出文件
int dst_bufsize = ret;
for (int idx = 0; idx < MAX_FRAME_NUM; idx++)
{
    read_yuv_from_ifile(src_data, src_linesize, srcWidth, srcHeight, 0, files);
    read_yuv_from_ifile(src_data, src_linesize, srcWidth, srcHeight, 1, files);
    read_yuv_from_ifile(src_data, src_linesize, srcWidth, srcHeight, 2, files);

    sws_scale(sws_ctx, (const uint8_t * const*)src_data, src_linesize, 0, srcHeight, dst_data, dst_linesize);

    fwrite(dst_data[0], 1, dst_bufsize, files.oFile);
}

其核心函数为sws_scale,其声明为:

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[]);

该函数的各个参数比较容易理解,除了第一个是之前创建的SwsContext之外,其他基本上都是源和目标图像的缓存区和大小等。在写完一帧后,调用fwrite将输出的目标图像写入输出yuv文件中。

5. 收尾工作

收尾工作除了释放缓存区和关闭输入输出文件之外,就是需要释放SwsContext结构,需调用函数:sws_freeContext。实现过程为:

fclose(files.iFile);
fclose(files.oFile);
av_freep(&src_data[0]);
av_freep(&dst_data[0]);
sws_freeContext(sws_ctx);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FFmpeg是一套开源的跨平台音视频处理工具库,提供了音视频编解码、格式转换、过滤器等功能,广泛应用于多媒体开发领域。FFmpeg SDK则是基于FFmpeg的开发包,为开发者提供了更加友好的接口和封装,简化了音视频处理的开发流程。 使用FFmpeg SDK,开发者可以轻松地实现视频文件的读取、写入、编解码等操作。它支持众多音视频格式,包括但不限于MP4、AVI、FLV、MP3、AAC等,可以进行格式之间的转换和编码参数的调整。此外,FFmpeg SDK还支持多种常用编解码库,如x264、x265、libvpx、libaom等,使得开发者能够根据需要选用合适的编码方式。 FFmpeg SDK提供了一套完善的API文档,方便开发者查找和应用各种功能。开发者可以根据文档中的示例代码,快速上手并进行开发。同时,FFmpeg SDK还支持多线程和硬件加速等特性,可以提高音视频处理的效率和性能。 除了基本的音视频处理功能,FFmpeg SDK还支持视频截图、音频剪切、视频拼接等操作,满足了更多实际需求。而且,FFmpeg SDK的开源特性使得开发者可以根据自己的需要进行二次开发和优化,使其更加适用于自己的项目。 总之,FFmpeg SDK是一款强大的音视频处理开发包,提供了丰富的功能和灵活的接口,方便开发者进行各种音视频处理任务。无论是开发媒体播放器、视频编辑器还是实时流媒体处理,使用FFmpeg SDK都能有效简化开发流程,并获得高效的处理能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值