国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

FFmpeg+SDL實時解碼和渲染H264視頻流

這篇具有很好參考價值的文章主要介紹了FFmpeg+SDL實時解碼和渲染H264視頻流。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

之前實現(xiàn)了Android手機攝像頭數(shù)據(jù)的TCP實時傳輸,今天接著聊聊,如何在PC端把接收到的H264視頻流實時解碼并渲染出來。這次使用的語言是C++,框架有FFmpeg和SDL2。

解碼

解碼部分使用FFmpeg,首先,需要初始化H264解碼器:

int H264Decoder::init() {
    codec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (codec == nullptr) {
        printf("No H264 decoder found\n");
        return -1;
    }
    codecCtx = avcodec_alloc_context3(codec);
    codecCtx->flags |= AV_CODEC_FLAG_LOW_DELAY;
    if (avcodec_open2(codecCtx, codec, nullptr) < 0) {
        printf("Failed to open codec\n");
        return -2;
    }
    packet = av_packet_alloc();
    m_Frame = av_frame_alloc();
    parser = av_parser_init(AV_CODEC_ID_H264);
    return 0;
}

然后,使用創(chuàng)建TCP連接到我們的Android端,讀取數(shù)據(jù)包:

bool read_data(SOCKET socket, void* data, unsigned int len) {
    while (len > 0) {
        int ret = recv(socket, (char*)data, len, 0);
        if (ret <= 0) {
            return false;
        }
        len -= ret;
        data = (char*)data + ret;
    }
    return true;
}

bool read_int(SOCKET socket, ULONG* value) {
    bool ret = read_data(socket, value, 4);
    if (ret) {
        *value = ntohl(*value);
    }
    return ret;
}

int PacketReceiver::readPacket(unsigned char** data, unsigned long* size) {
    ULONG pkgSize = 0;
    bool ret = read_int(m_Socket, &pkgSize);
    if (!ret) {
        printf("Failed to read packet size\n");
        return -1;
    }
    if (m_DataLen < pkgSize) {
        if (m_Data != nullptr) {
            delete[] m_Data;
        }
        m_Data = new unsigned char[pkgSize];
        m_DataLen = pkgSize;
    }
    if (!read_data(m_Socket, m_Data, pkgSize)) {
        printf("Failed to read packet data\n");
        return -2;
    }
    *data = m_Data;
    *size = pkgSize;
    return 0;
}

再把每個數(shù)據(jù)包傳送給H264解碼器解碼

int H264Decoder::decode(unsigned char* data, int size, AVFrame** frame) {
    int new_pkg_ret = av_new_packet(packet, size);
    if (new_pkg_ret != 0) {
        printf("Failed to create new packet\n");
        return -1;
    }
    memcpy(packet->data, data, size);
    int ret = avcodec_send_packet(codecCtx, packet);
    if (ret < 0 && ret != AVERROR(EAGAIN)) {
        printf("Failed to parse packet\n");
        return -1;
    }
    ret = avcodec_receive_frame(codecCtx, m_Frame);
    if (ret == AVERROR(EAGAIN)) {
        *frame = nullptr;
        return 0;
    }
    if (ret != 0) {
        printf("Failed to read frame\n");
        return -1;
    }
    *frame = m_Frame;
    av_packet_unref(packet);
    return 0;
}

解碼器解碼后,最終得到的是AVFrame對象,代表一幀畫面,數(shù)據(jù)格式一般為YUV格式(跟編碼端選擇的像素格式有關(guān))。

渲染

通過使用SDL2,我們可以直接渲染YUV數(shù)據(jù),無需手動轉(zhuǎn)成RGB。

首先,我們先初始化SDL2并創(chuàng)建渲染窗口:

int YuvRender::init(int video_width, int video_height) {
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Rect bounds;
    SDL_GetDisplayUsableBounds(0, &bounds);
    int winWidth = video_width;
    int winHeight = video_height;
    if (winWidth > bounds.w || winHeight > bounds.h) {
        float widthRatio = 1.0 * winWidth / bounds.w;
        float heightRatio = 1.0 * winHeight / bounds.h;
        float maxRatio = widthRatio > heightRatio ? widthRatio : heightRatio;
        winWidth = int(winWidth / maxRatio);
        winHeight = int(winHeight / maxRatio);
    }
    SDL_Window* window = SDL_CreateWindow(
        "NetCameraViewer",
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        winWidth,
        winHeight,
        SDL_WINDOW_OPENGL
    );
    m_Renderer = SDL_CreateRenderer(window, -1, 0);
    m_Texture = SDL_CreateTexture(
        m_Renderer,
        SDL_PIXELFORMAT_IYUV,
        SDL_TEXTUREACCESS_STREAMING,
        video_width,
        video_height
    );
    m_VideoWidth = video_width;
    m_VideoHeight = video_height;
    m_Rect.x = 0;
    m_Rect.y = 0;
    m_Rect.w = winWidth;
    m_Rect.h = winHeight;
    return 0;
}

每次解碼出一幀畫面的時候,再調(diào)用render函數(shù)渲染:

int YuvRender::render(unsigned char* data[], int pitch[]) {
    int uvHeight = m_VideoHeight / 2;
    int ySize = pitch[0] * m_VideoHeight;
    int uSize = pitch[1] * uvHeight;
    int vSize = pitch[2] * uvHeight;
    int buffSize =  ySize + uSize + vSize;
    if (m_FrameBufferSize < buffSize) {
        if (m_FrameBuffer != nullptr) {
            delete[] m_FrameBuffer;
        }
        m_FrameBuffer = new unsigned char[buffSize];
        m_FrameBufferSize = buffSize;
    }
    SDL_memcpy(m_FrameBuffer, data[0], ySize);
    SDL_memcpy(m_FrameBuffer + ySize, data[1], uSize);
    SDL_memcpy(m_FrameBuffer + ySize + uSize, data[2], vSize);
    SDL_UpdateTexture(m_Texture, NULL, m_FrameBuffer, pitch[0]);
    SDL_RenderClear(m_Renderer);
    SDL_RenderCopy(m_Renderer, m_Texture, NULL, &m_Rect);
    SDL_RenderPresent(m_Renderer);
    SDL_PollEvent(&m_Event);
    if (m_Event.type == SDL_QUIT) {
        exit(0);
    }
    return 0;
}

性能

在搭載AMD Ryzen 5 5600U的機器上,1800 x 1350的分辨率,解碼一幀平均25ms, 渲染1~2ms,加上編碼和傳輸延時,總體延時在70ms左右。

完整源碼已上傳至Github: https://github.com/kasonyang/net-camera/tree/main/viewer-app文章來源地址http://www.zghlxwxcb.cn/news/detail-544437.html

到了這里,關(guān)于FFmpeg+SDL實時解碼和渲染H264視頻流的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 音視頻——視頻流H264編碼格式

    音視頻——視頻流H264編碼格式

    我們了解了什么是宏快,宏快作為壓縮視頻的最小的一部分,需要被組織,然后在網(wǎng)絡(luò)之間做相互傳輸。 H264更深層次 —》宏塊 太淺了 ? 如果單純的用 宏快 來發(fā)送數(shù)據(jù)是 雜亂無章 的,就好像在沒有 集裝箱 出現(xiàn)之前,貨物總是隨意被堆放到船上。 上貨(編碼),下貨是非

    2024年02月15日
    瀏覽(26)
  • JAVA實現(xiàn)H264視頻流推送到RTSP、RTMP服務(wù)----JavaCV

    前提: 1.準備好rtsp、rtmp服務(wù) 2.準備好視頻流接收程序 基本思路是:啟動兩個線程,線程1接收視頻流,線程2使用JavaCV將視頻流推送到RTSP、RTMP服務(wù),兩者之間使用管道流進行通信。線程2接收到視頻流后的具體操作:啟動grabber接收視頻流并捕獲視頻幀,然后啟動recoder將捕獲的

    2024年02月11日
    瀏覽(31)
  • 【vue2】前端如何播放rtsp 視頻流,拿到rtsp視頻流地址如何處理,??狄曨lrtsp h264 如何播放

    【vue2】前端如何播放rtsp 視頻流,拿到rtsp視頻流地址如何處理,??狄曨lrtsp h264 如何播放

    最近在寫vue2 項目其中有個需求是實時播放攝像頭的視頻,攝像頭是 ???的設(shè)備,搞了很長時間終于監(jiān)控視頻出來了,記錄一下,放置下次遇到。文章有點長,略顯啰嗦請耐心看完。 測試?測試什么?測試rtsp視頻流能不能播放。 video mediaplay官網(wǎng) 即(VLC) 下載、安裝完VLC后

    2024年02月05日
    瀏覽(24)
  • 【FFmpeg學(xué)習(xí)】H264 視頻碼流分析

    【FFmpeg學(xué)習(xí)】H264 視頻碼流分析

    NAL層:(Network Abstraction Layer,視頻數(shù)據(jù)網(wǎng)絡(luò)抽象層): 它的作用是H264只要在網(wǎng)絡(luò)上傳輸,在傳輸?shù)倪^程每個包以太網(wǎng)是1500字節(jié),而H264的幀往往會大于1500字節(jié),所以要進行拆包,將一個幀拆成多個包進行傳輸,所有的拆包或者組包都是通過NAL層去處理的。 VCL層:(Video Coding L

    2024年02月02日
    瀏覽(34)
  • 音視頻處理 ffmpeg中級開發(fā) H264編碼

    音視頻處理 ffmpeg中級開發(fā) H264編碼

    libavcodec/avcodec.h 常用的數(shù)據(jù)結(jié)構(gòu) AVCodec 編碼器結(jié)構(gòu)體 AVCodecContext 編碼器上下文 AVFrame 解碼后的幀 結(jié)構(gòu)體內(nèi)存的分配和釋放 av_frame_alloc 申請 av_frame_free() 釋放 avcodec_alloc_context3() 創(chuàng)建編碼器上下文 avcodec_free_context() 釋放編碼器上下文 解碼步驟 avcodec_find_decoder 查找解碼器 avcod

    2024年02月01日
    瀏覽(109)
  • ffmpeg學(xué)習(xí)日記604-指令-將視頻格式轉(zhuǎn)為H264格式

    ffmpeg學(xué)習(xí)日記604-指令-將視頻格式轉(zhuǎn)為H264格式 在第四篇中,想要解碼視頻,缺沒有弄清楚怎樣的一個數(shù)據(jù)流,現(xiàn)在又明晰了一點,所謂的h264編解碼,并不是直接將視頻格式,通過h264編解碼為視頻原始數(shù)據(jù)流,這種說法是錯誤的,而是應(yīng)該將視頻格式轉(zhuǎn)換為h264的數(shù)據(jù)流,然后

    2024年02月11日
    瀏覽(20)
  • 【音視頻處理】轉(zhuǎn)編碼H264 to H265,F(xiàn)Fmpeg,代碼分享講解

    【音視頻處理】轉(zhuǎn)編碼H264 to H265,F(xiàn)Fmpeg,代碼分享講解

    大家好,歡迎來到停止重構(gòu)的頻道。 本期我們討論音視頻文件 轉(zhuǎn)編碼 ,如將視頻H264轉(zhuǎn)H265等。 內(nèi)容中所提及的 代碼都會放在GitHub ,感興趣的小伙伴可以到GitHub下載。 我們按這樣的順序展開討論:? 1、??編碼的作用? 2、??轉(zhuǎn)編碼的工作原理 3、??編解碼器安裝? 4、??示

    2024年02月11日
    瀏覽(27)
  • FFmpeg 解碼 H.264 視頻出現(xiàn)花屏和馬賽克的解決辦法

    FFmpeg 解碼 H.264 視頻出現(xiàn)花屏和馬賽克的解決辦法

    發(fā)送數(shù)據(jù)包太大,超過了 FFmpeg 的默認最大值。 網(wǎng)絡(luò)情況較差時,因網(wǎng)絡(luò)狀況出現(xiàn)的丟包。 解碼出錯。 包亂序。 一種方法是控制播放源的發(fā)送數(shù)據(jù)大小,但這極大浪費了當(dāng)前的網(wǎng)絡(luò)帶寬,非優(yōu)選方案。 更好的做法是擴大接收端的接收緩沖區(qū),其修改方法為: 在 FFmpeg 的源碼

    2024年04月26日
    瀏覽(33)
  • 記錄對接??低晹z像頭web端實時預(yù)覽:Linux+ffmpeg+nginx轉(zhuǎn)換RTSP視頻流(完整版實現(xiàn))

    ????????需求:web端實現(xiàn)??禂z像頭實時預(yù)覽效果 ????????由于市面上大部分網(wǎng)絡(luò)攝像頭都支持RTSP協(xié)議視頻流,web端一般無法直接使用RTSP實現(xiàn)視頻預(yù)覽,本篇使用ffmpeg對視頻流進行轉(zhuǎn)換,最終實現(xiàn)web端實時預(yù)覽。 ????????工具介紹:ffmpeg、nginx、vue ????????介

    2024年01月25日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包