zoukankan      html  css  js  c++  java
  • FFmpeg(10)-利用FFmpeg进行视频像素格式和尺寸的转换(sws_getCachedContext(), sws_scale())

    一.包含头文件和库文件

    像素格式的相关函数包含在 libswscale.so 库中,CMakeLists需要做下列改动:

    # swscale
    add_library(swscale SHARED IMPORTED)
    set_target_properties(swscale PROPERTIES IMPORTED_LOCATION ${FF}/libswscale.so)

    target_link_libraries

    target_link_libraries( # Specifies the target library.
                           native-lib
                           avcodec
                           avformat
                           avutil
                           swscale
    
                           # Links the target library to the log library
                           # included in the NDK.
                           ${log-lib} )

    同时在代码中包含头文件 #include <libswscale/swscale.h> 

    二. 相关函数说明

    a)

    sws_getContext()                                                        // 像素格式转换的上下文。会创建新的空间

    struct SwsContext *sws_getCachedContext();           // 函数名补全。会根据传入的上下文到缓冲里面去找。

    参数说明:

    1. 第一参数可以传NULL,默认会开辟一块新的空间。
    2. srcW,srcH, srcFormat, 原始数据的宽高和原始像素格式(YUV420),
    3. dstW,dstH,dstFormat;   目标宽,目标高,目标的像素格式(这里的宽高可能是手机屏幕分辨率,RGBA8888),这里不仅仅包含了尺寸的转换和像素格式的转换
    4. flag 提供了一系列的算法,快速线性,差值,矩阵,不同的算法性能也不同,快速线性算法性能相对较高。只针对尺寸的变换。对像素格式转换无此问题
    5. #define SWS_FAST_BILINEAR 1

      #define SWS_BILINEAR 2

      #define SWS_BICUBIC 4

      #define SWS_X      8

      #define SWS_POINT 0x10

      #define SWS_AREA 0x20

      #define SWS_BICUBLIN 0x40

    后面还有两个参数是做过滤器用的,一般用不到,传NULL,最后一个参数是跟flag算法相关,也可以传NULL。

    b)

     int sws_scale();

    具体每一帧数据的处理。

    struct SwsContext *c                   // 像素格式转换的上下文

    uint8_t *const srcSlice[]                // src的Slice,对应的具体数据的数组,是指针数组,也就是二维数组,YUV420P(三行数据)

    const int srcStride[]                      // linesize, 一行对应的大小。

    int srcSliceY                                 // 用不到,直接传0即可。

    int srcSliceH                                // 图像的高度。

    uint8_t *const dst[]                      // 目标的地址。也是一个指针数组。

    const int dstStride[]                     // 输入的linesize

    三, 相关代码参考

    // 初始化像素格式转换上下文
        SwsContext *vctx = NULL;
        int outWidth = 1280;
        int outHeight = 720;
        char *rgb = new char[1920*1080*4];
    
        for (;;) {
    
            if (getNowMs() - start >= 3000) {
                LOGI("now decoder fps is: %d", frameCount / 3);
                start = getNowMs();
                frameCount = 0;
            }
            int ret = av_read_frame(ic, packet);
            if (ret != 0) {
                LOGE("读取到结尾处");
                int pos = 20 * r2d(ic->streams[videoStream]->time_base);
                // 改变播放进度
                av_seek_frame(ic, videoStream, pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);
                continue;
            }
    
    //        LOGI("Read a Packet. streamIndex=%d, size=%d, pts=%lld, flag=%d",
    //             packet->stream_index,
    //             packet->size,
    //             packet->pts,
    //             packet->flags
    //        );
    
            AVCodecContext *cc = vc;
            if (packet->stream_index == audioStream) cc = ac;
            // 发送到线程中去解码(将packet写入到解码队列当中去)
            ret = avcodec_send_packet(cc, packet);
            // 清理
            int p = packet->pts;
            av_packet_unref(packet);
            if (ret != 0) {
                // LOGE("avcodec_send_packet failed.");
                continue;
            }
    
            for(;;) {
                // 从已解码成功的数据当中取出一个frame, 要注意send一次,receive不一定是一次
                ret = avcodec_receive_frame(cc, frame);
                if (ret != 0) {
                    break;
                }
                if (cc == vc) {
                    frameCount++;
                    vctx = sws_getCachedContext(
                            vctx,
                            frame->width,
                            frame->height,
                            (AVPixelFormat)frame->format,
                            outWidth,
                            outHeight,
                            AV_PIX_FMT_RGBA,
                            SWS_FAST_BILINEAR,
                            0, 0, 0
                    );
                    if (!vctx) {
                        LOGE("sws_getCachedContext failed!");
                    } else {
                        // 开始像素格式转换
                        uint8_t  *data[AV_NUM_DATA_POINTERS] = {0};
                        data[0] = (uint8_t *)rgb;
                        int lines[AV_NUM_DATA_POINTERS] = {0};
                        lines[0] = outWidth * 4;
                        int h = sws_scale(
                                vctx,
                                (const uint8_t **)frame->data,
                                frame->linesize,
                                0,
                                frame->height,
                                data, lines
                        );
                        LOGI("sws_scale = %d", h);
                    }
                }
                // LOGI("Receive a frame.........");
            }
        }
  • 相关阅读:
    docker – 在容器引擎上定义/ dev / shm的大小
    Redis集群创建
    Go 语言陷阱
    使用python进行视频图片提取
    使用ffmpeg进行视频图片提取
    app端性能测试
    为什么需要分布式ID?你项目中是怎么做的?
    JavaGuide学习记录——java容器
    【追根究底】doCreateBean中为什么会对earlySingletonExposure处理两次
    老板急坏了,公司网站的 HTTPS 过期了,获取免费SSL证书
  • 原文地址:https://www.cnblogs.com/yongdaimi/p/9829290.html
Copyright © 2011-2022 走看看