分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.youkuaiyun.com/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
=====================================================
FFmpeg的库函数源代码分析文章列表:
【架构图】
【通用】
FFmpeg 源代码简单分析:av_register_all()
FFmpeg 源代码简单分析:avcodec_register_all()
FFmpeg 源代码简单分析:内存的分配和释放(av_malloc()、av_free()等)
FFmpeg 源代码简单分析:常见结构体的初始化和销毁(AVFormatContext,AVFrame等)
FFmpeg 源代码简单分析:av_find_decoder()和av_find_encoder()
FFmpeg 源代码简单分析:avcodec_open2()
FFmpeg 源代码简单分析:avcodec_close()
【解码】
图解FFMPEG打开媒体的函数avformat_open_input
FFmpeg 源代码简单分析:avformat_open_input()
FFmpeg 源代码简单分析:avformat_find_stream_info()
FFmpeg 源代码简单分析:av_read_frame()
FFmpeg 源代码简单分析:avcodec_decode_video2()
FFmpeg 源代码简单分析:avformat_close_input()
【编码】
FFmpeg 源代码简单分析:avformat_alloc_output_context2()
FFmpeg 源代码简单分析:avformat_write_header()
FFmpeg 源代码简单分析:avcodec_encode_video()
FFmpeg 源代码简单分析:av_write_frame()
FFmpeg 源代码简单分析:av_write_trailer()
【其它】
FFmpeg源代码简单分析:日志输出系统(av_log()等)
FFmpeg源代码简单分析:结构体成员管理系统-AVClass
FFmpeg源代码简单分析:结构体成员管理系统-AVOption
FFmpeg源代码简单分析:libswscale的sws_getContext()
FFmpeg源代码简单分析:libswscale的sws_scale()
FFmpeg源代码简单分析:libavdevice的avdevice_register_all()
FFmpeg源代码简单分析:libavdevice的gdigrab
【脚本】
【H.264】
=====================================================
本文继续上一篇文章《FFmpeg源代码分析:sws_getContext()》的内容,简单分析FFmpeg的图像处理(缩放,YUV/RGB格式转换)类库libswsscale中的sws_scale()函数。libswscale是一个主要用于处理图片像素数据的类库。可以完成图片像素格式的转换,图片的拉伸等工作。有关libswscale的使用可以参考文章:
《最简单的基于FFmpeg的libswscale的示例(YUV转RGB)》
该类库常用的函数数量很少,一般情况下就3个:
sws_getContext():初始化一个SwsContext。
sws_scale():处理图像数据。
sws_freeContext():释放一个SwsContext。
在分析sws_scale()的源代码之前,先简单回顾一下上篇文章中分析得到的两张图。
函数调用结构图
分析得到的libswscale的函数调用关系如下图所示。

Libswscale处理数据流程
Libswscale处理像素数据的流程可以概括为下图。

XXX to YUV Converter:首相将数据像素数据转换为8bitYUV格式;
Horizontal scaler:水平拉伸图像,并且转换为15bitYUV;
Vertical scaler:垂直拉伸图像;
Output converter:转换为输出像素格式。
sws_scale()
sws_scale()是用于转换像素的函数。它的声明位于libswscale\swscale.h,如下所示。
/** * Scale the image slice in srcSlice and put the resulting scaled * slice in the image in dst. A slice is a sequence of consecutive * rows in an image. * * Slices have to be provided in sequential order, either in * top-bottom or bottom-top order. If slices are provided in * non-sequential order the behavior of the function is undefined. * * @param c the scaling context previously created with * sws_getContext() * @param srcSlice the array containing the pointers to the planes of * the source slice * @param srcStride the array containing the strides for each plane of * the source image * @param srcSliceY the position in the source image of the slice to * process, that is the number (counted starting from * zero) in the image of the first row of the slice * @param srcSliceH the height of the source slice, that is the number * of rows in the slice * @param dst the array containing the pointers to the planes of * the destination image * @param dstStride the array containing the strides for each plane of * the destination image * @return the height of the output slice */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_scale()的定义位于libswscale\swscale.c,如下所示。
/** * swscale wrapper, so we don't need to export the SwsContext. * Assumes planar YUV to be in YUV order instead of YVU. */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[]){ int i, ret; const uint8_t *src2[4]; uint8_t *dst2[4]; uint8_t *rgb0_tmp = NULL; //检查输入参数 if (!srcStride || !dstStride || !dst || !srcSlice) { av_log(c, AV_LOG_ERROR, "One of the input parameters to sws_scale() is NULL, please check the calling code\n"); return 0; } if (c->cascaded_context[0] && srcSliceY == 0 && srcSliceH == c->cascaded_context[0]->srcH) { ret = sws_scale(c->cascaded_context[0], srcSlice, srcStride, srcSliceY, srcSliceH, c->cascaded_tmp, c->cascaded_tmpStride); if (ret < 0) return ret; ret = sws_scale(c->cascaded_context[1], (const uint8_t * const * )c->cascaded_tmp, c->cascaded_tmpStride, 0, c->cascaded_context[0]->dstH, dst, dstStride); return ret; } memcpy(src2, srcSlice, sizeof(src2)); memcpy(dst2, dst, sizeof(dst2)); // do not mess up sliceDir if we have a "trailing" 0-size slice if (srcSliceH == 0) return 0; //检查 if (!check_image_pointers(srcSlice, c->srcFormat, srcStride)) { av_log(c, AV_LOG_ERROR, "bad src image pointers\n"); return 0; } if (!check_image_pointers((const uint8_t* const*)dst, c->dstFormat, dstStride)) { av_log(c, AV_LOG_ERROR, "bad dst image pointers\n"); return 0; } if (c->sliceDir == 0 && srcSliceY != 0 && srcSliceY + srcSliceH != c->srcH) { av_log(c, AV_LOG_ERROR, "Slices start in the middle!\n"); return 0; } if (c->sliceDir == 0) { if (srcSliceY == 0) c->sliceDir = 1; else c->sliceDir = -1; } //使用调色板palette的特殊处理?应该不常见 if (usePal(c->srcFormat)) { for (i = 0; i < 256; i++) { int r, g, b, y, u, v, a = 0xff; if (c->srcFormat == AV_PIX_FMT_PAL8) { uint32_t p = ((const uint32_t *)(srcSlice[1]))[i]; a = (p >> 24) & 0xFF; r = (p >> 16) & 0xFF; g = (p >> 8) & 0xFF; b = p & 0xFF; } else if (c->srcFormat == AV_PIX_FMT_RGB8) { r = ( i >> 5 ) * 36; g = ((i >> 2) & 7) * 36; b = ( i & 3) * 85; } else if (c->srcFormat == AV_PIX_FMT_BGR8) { b = ( i >> 6 ) * 85; g = ((i >> 3) & 7) * 36; r = ( i & 7) * 36; } else if (c->srcFormat == AV_PIX_FMT_RGB4_BYTE) { r = ( i >> 3 ) * 255; g = ((i >> 1) & 3) * 85; b = ( i & 1) * 255; } else if (c->srcFormat == AV_PIX_FMT_GRAY8 || c->srcFormat == AV_PIX_FMT_GRAY8A) { r = g = b = i; } else { av_assert1(c->srcFormat == AV_PIX_FMT_BGR4_BYTE); b = ( i >> 3 ) * 255; g = ((i >> 1) & 3) * 85; r = ( i & 1) * 255; }#define RGB2YUV_SHIFT 15#define BY ( (int) (0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))#define BV (-(int) (0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))#define BU ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))#define GY ( (int) (0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))#define GV (-(int) (0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))#define GU (-(int) (0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))#define RY ( (int) (0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))#define RV ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))#define RU (-(int) (0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5)) y = av_clip_uint8((RY * r + GY * g + BY * b + ( 33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT); u = av_clip_uint8((RU * r + GU * g + BU * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT); v = av_clip_uint8((RV * r + GV * g + BV * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT); c->pal_yuv[i]= y + (u<<8) + (v<<16) + ((unsigned)a<<24); switch (c->dstFormat) { case AV_PIX_FMT_BGR32:#if !HAVE_BIGENDIAN case AV_PIX_FMT_RGB24:#endif c->pal_rgb[i]= r + (g<<8) + (b<<16) + ((unsigned)a<<24); break; case AV_PIX_FMT_BGR32_1:#if HAVE_BIGENDIAN case AV_PIX_FMT_BGR24:#endif c->pal_rgb[i]= a + (r<<8) + (g<<16) + ((unsigned)b<<24); break; case AV_PIX_FMT_RGB32_1:#if HAVE_BIGENDIAN