ffmpeg关于sws_scale的那些事儿

随便聊聊,sws_scale 在对rgb处理上,基本都是把数据放于一个通道,而且针对行来扫描,所以linedata就是图像的宽 * 通道数,而在对yuv的处理上,基本上都是依据具体的格式,分为三个通道来处理

下面对其函数参数进行详细说明:

1.参数 SwsContext *c, 转换格式的上下文。也就是 sws_getContext 函数返回的结果。
2.参数 const uint8_t *const srcSlice[], 输入图像的每个颜色通道的数据指针。其实就是解码后的AVFrame中的data[]数组。因为不同像素的存储格式不同,所以srcSlice[]维数
也有可能不同。
以YUV420P为例,它是planar格式,它的内存中的排布如下:
YYYYYYYY UUUU VVVV
使用FFmpeg解码后存储在AVFrame的data[]数组中时:
data[0]——-Y分量, Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y8……
data[1]——-U分量, U1, U2, U3, U4……
data[2]——-V分量, V1, V2, V3, V4……
linesize[]数组中保存的是对应通道的数据宽度 ,
linesize[0]——-Y分量的宽度
linesize[1]——-U分量的宽度
linesize[2]——-V分量的宽度

而RGB24,它是packed格式,它在data[]数组中则只有一维,它在存储方式如下:
data[0]: R1, G1, B1, R2, G2, B2, R3, G3, B3, R4, G4, B4……
这里要特别注意,linesize[0]的值并不一定等于图片的宽度,有时候为了对齐各解码器的CPU,实际尺寸会大于图片的宽度,这点在我们编程时(比如OpengGL硬件转换/渲染)要特别注意,否则解码出来的图像会异常。

3.参数const int srcStride[],输入图像的每个颜色通道的跨度。.也就是每个通道的行字节数,对应的是解码后的AVFrame中的linesize[]数组。根据它可以确立下一行的起始位置,不过stride和width不一定相同,这是因为:
a.由于数据帧存储的对齐,有可能会向每行后面增加一些填充字节这样 stride = width + N;
b.packet色彩空间下,每个像素几个通道数据混合在一起,例如RGB24,每个像素3字节连续存放,因此下一行的位置需要跳过3*width字节。

4.参数int srcSliceY, int srcSliceH,定义在输入图像上处理区域,srcSliceY是起始位置,srcSliceH是处理多少行。如果srcSliceY=0,srcSliceH=height,表示一次性处理完整个图像。这种设置是为了多线程并行,例如可以创建两个线程,第一个线程处理 [0, h/2-1]行,第二个线程处理 [h/2, h-1]行。并行处理加快速度。
5.参数uint8_t *const dst[], const int dstStride[]定义输出图像信息(输出的每个颜色通道数据指针,每个颜色通道行字节数)

某博主写的帖子还是很到位的,Y分量数据,U分量数据,V分量数据,以及每个分量的宽度,完成图像的缩放简直so easy。

 

比如,针对bgra的长宽的裸流缩放为适当的rgb的裸流,其代码如下:

    AVFrame *nDst = nullptr;
	nDst = av_frame_alloc();
	nDst->width = nDstW;
	nDst->height = nDstH;
	nDst->format = AV_PIX_FMT_RGB24;
	av_frame_get_buffer(nDst, 1);
	unsigned char *srcBuff[4] = { (unsigned char *)src,nullptr,nullptr,nullptr };
	int srcStride[4] = { 4 * nSrcW,0,0,0 };
	
	SwsContext*	m_pSwsContext = nullptr;

	m_pSwsContext = sws_getContext(nSrcW, nSrcH, AV_PIX_FMT_BGRA,
		nDstW, nDstH, AV_PIX_FMT_RGB24,
		SWS_SINC,
		NULL, NULL, NULL);

	unsigned char *fdst[AV_NUM_DATA_POINTERS] = {0};
	int lines[AV_NUM_DATA_POINTERS] = { 0 };
	int ret = sws_scale(m_pSwsContext, srcBuff,
		srcStride, 0, nSrcH,
		nDst->data, nDst->linesize);

	sws_freeContext(m_pSwsContext);

至于yuv转rgb的代码,还是引用雷神的代码

#include 
 
 
extern "C"
{
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
};
 
 
int main(int argc, char* argv[])
{
    //Parameters    
    FILE *src_file =fopen("sintel_480x272_yuv420p.yuv", "rb");
    const int src_w=480,src_h=272;
    AVPixelFormat src_pixfmt=AV_PIX_FMT_YUV420P;
 
    int src_bpp=av_get_bits_per_pixel(av_pix_fmt_desc_get(src_pixfmt));
 
    FILE *dst_file = fopen("sintel_1280x720_rgb24.rgb", "wb");
    const int dst_w=1280,dst_h=720;
    AVPixelFormat dst_pixfmt=AV_PIX_FMT_RGB24;
    int dst_bpp=av_get_bits_per_pixel(av_pix_fmt_desc_get(dst_pixfmt));
 
    //Structures
    uint8_t *src_data[4];
    int src_linesize[4];
 
    uint8_t *dst_data[4];
    int dst_linesize[4];
 
    int rescale_method=SWS_BICUBIC;
    struct SwsContext *img_convert_ctx;
    uint8_t *temp_buffer=(uint8_t *)malloc(src_w*src_h*src_bpp/8);
     
    int frame_idx=0;
    int ret=0;
    ret= av_image_alloc(src_data, src_linesize,src_w, src_h, src_pixfmt, 1);
    if (ret< 0) {
        printf( "Could not allocate source image\n");
        return -1;
    }
    ret = av_image_alloc(dst_data, dst_linesize,dst_w, dst_h, dst_pixfmt, 1);
    if (ret< 0) {
        printf( "Could not allocate destination image\n");
        return -1;
    }
    //----------------------------- 
    //Init Method 1
    img_convert_ctx =sws_alloc_context();
    //Show AVOption
    av_opt_show2(img_convert_ctx,stdout,AV_OPT_FLAG_VIDEO_PARAM,NULL);
    //Set Value
    av_opt_set_int(img_convert_ctx,"sws_flags",SWS_BICUBIC|SWS_PRINT_INFO,NULL);
    av_opt_set_int(img_convert_ctx,"srcw",src_w,NULL);
    av_opt_set_int(img_convert_ctx,"srch",src_h,NULL);
    av_opt_set_int(img_convert_ctx,"src_format",src_pixfmt,NULL);
    //'0' for MPEG (Y:0-235);'1' for JPEG (Y:0-255)
    av_opt_set_int(img_convert_ctx,"src_range",1,NULL);
    av_opt_set_int(img_convert_ctx,"dstw",dst_w,NULL);
    av_opt_set_int(img_convert_ctx,"dsth",dst_h,NULL);
    av_opt_set_int(img_convert_ctx,"dst_format",dst_pixfmt,NULL);
    av_opt_set_int(img_convert_ctx,"dst_range",1,NULL);
    sws_init_context(img_convert_ctx,NULL,NULL);
 
    //Init Method 2
    //img_convert_ctx = sws_getContext(src_w, src_h,src_pixfmt, dst_w, dst_h, dst_pixfmt, 
    //  rescale_method, NULL, NULL, NULL); 
    //-----------------------------
    /*
    //Colorspace
    ret=sws_setColorspaceDetails(img_convert_ctx,sws_getCoefficients(SWS_CS_ITU601),0,
        sws_getCoefficients(SWS_CS_ITU709),0,
         0, 1 << 16, 1 << 16);
    if (ret==-1) {
        printf( "Colorspace not support.\n");
        return -1;
    }
    */
    while(1)
    {
        if (fread(temp_buffer, 1, src_w*src_h*src_bpp/8, src_file) != src_w*src_h*src_bpp/8){
            break;
        }
         
        switch(src_pixfmt){
        case AV_PIX_FMT_GRAY8:{
            memcpy(src_data[0],temp_buffer,src_w*src_h);
            break;
                              }
        case AV_PIX_FMT_YUV420P:{
            memcpy(src_data[0],temp_buffer,src_w*src_h);                    //Y
            memcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h/4);      //U
            memcpy(src_data[2],temp_buffer+src_w*src_h*5/4,src_w*src_h/4);  //V
            break;
                                }
        case AV_PIX_FMT_YUV422P:{
            memcpy(src_data[0],temp_buffer,src_w*src_h);                    //Y
            memcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h/2);      //U
            memcpy(src_data[2],temp_buffer+src_w*src_h*3/2,src_w*src_h/2);  //V
            break;
                                }
        case AV_PIX_FMT_YUV444P:{
            memcpy(src_data[0],temp_buffer,src_w*src_h);                    //Y
            memcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h);        //U
            memcpy(src_data[2],temp_buffer+src_w*src_h*2,src_w*src_h);      //V
            break;
                                }
        case AV_PIX_FMT_YUYV422:{
            memcpy(src_data[0],temp_buffer,src_w*src_h*2);                  //Packed
            break;
                                }
        case AV_PIX_FMT_RGB24:{
            memcpy(src_data[0],temp_buffer,src_w*src_h*3);                  //Packed
            break;
                                }
        default:{
            printf("Not Support Input Pixel Format.\n");
            break;
                              }
        }
         
        sws_scale(img_convert_ctx, src_data, src_linesize, 0, src_h, dst_data, dst_linesize);
        printf("Finish process frame %5d\n",frame_idx);
        frame_idx++;
 
        switch(dst_pixfmt){
        case AV_PIX_FMT_GRAY8:{
            fwrite(dst_data[0],1,dst_w*dst_h,dst_file); 
            break;
                              }
        case AV_PIX_FMT_YUV420P:{
            fwrite(dst_data[0],1,dst_w*dst_h,dst_file);                 //Y
            fwrite(dst_data[1],1,dst_w*dst_h/4,dst_file);               //U
            fwrite(dst_data[2],1,dst_w*dst_h/4,dst_file);               //V
            break;
                                }
        case AV_PIX_FMT_YUV422P:{
            fwrite(dst_data[0],1,dst_w*dst_h,dst_file);                 //Y
            fwrite(dst_data[1],1,dst_w*dst_h/2,dst_file);               //U
            fwrite(dst_data[2],1,dst_w*dst_h/2,dst_file);               //V
            break;
                                }
        case AV_PIX_FMT_YUV444P:{
            fwrite(dst_data[0],1,dst_w*dst_h,dst_file);                 //Y
            fwrite(dst_data[1],1,dst_w*dst_h,dst_file);                 //U
            fwrite(dst_data[2],1,dst_w*dst_h,dst_file);                 //V
            break;
                                }
        case AV_PIX_FMT_YUYV422:{
            fwrite(dst_data[0],1,dst_w*dst_h*2,dst_file);               //Packed
            break;
                                }
        case AV_PIX_FMT_RGB24:{
            fwrite(dst_data[0],1,dst_w*dst_h*3,dst_file);               //Packed
            break;
                              }
        default:{
            printf("Not Support Output Pixel Format.\n");
            break;
                            }
        }
    }
 
    sws_freeContext(img_convert_ctx);
 
    free(temp_buffer);
    fclose(dst_file);
    av_freep(&src_data[0]);
    av_freep(&dst_data[0]);
 
    return 0;
}

此文章引用链接如下:

https://www.oschina.net/code/snippet_230937_45233

你可能感兴趣的:(流媒体)