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.........");
        }
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM