1. 程式人生 > >ffmpeg解碼網路rtp流(包裝的h264)

ffmpeg解碼網路rtp流(包裝的h264)

最近接了一個做ffmpeg解碼的專案,客戶的視訊都是在伺服器上編碼的(H264編碼),編碼後的資料通過rtp封裝傳送到客戶端,客戶端負責解碼顯示。

前期準備:
下載ffmpeg編譯ios版本

檢視ffmpeg的例子程式碼,結果發現都是基於讀檔案的例子,相信很多沒有做過的朋友肯定很著急,呵呵,現在本主給你們發福利了,我把我的程式碼貼上來,
免得後面涉及到這方面的同學走彎路。

標頭檔案如下:
//
//  H264Decoder.h
//  MICloudPub
//
//  Created by chenjianjun on 14-6-3.
//  Copyright (c) 2014年 hy. All rights reserved.
//

#ifndef __MICloudPub___H264Decoder__
#define __MICloudPub___H264Decoder__

#define X264_DECODER_H long

class H264Decoder
{
public:
    H264Decoder(){}
    ~H264Decoder(){}
public:
    // H264解碼初期化
    X264_DECODER_H X264Decoder_Init();
    
    /*
     H264資料解碼,解碼後的資料為yuv420格式
     dwHandle:初期化時返回的控制代碼
     pDataIn:待解碼資料
     nInSize:待解碼資料長度
     pDataOut:解碼後的資料,儲存空間由呼叫者申請
     nOutSize:儲存空間大小
     
     nWidth:解碼後的影象寬度
     nHeight:解碼後的影象高度
     */
    int X264Decoder_Decode(X264_DECODER_H dwHandle, uint8_t *pDataIn, int nInSize, uint8_t *pDataOut, int nOutSize, int *nWidth, int *nHeight);
    
    /*
     H264解碼銷燬
     dwHandle:初期化時返回的控制代碼
     */
    void X264Decoder_UnInit(X264_DECODER_H dwHandle);
    
protected:
    void pgm_save2(unsigned char *buf, int wrap, int xsize, int ysize, uint8_t *pDataOut)
    {
        int i;
        for(i = 0; i < ysize; i++)
        {
            memcpy(pDataOut+i*xsize, buf + /*(ysize-i)*/i * wrap, xsize);
        }
    }
};

#endif /* defined(__MICloudPub___64Decoder__) */


cpp檔案如下:
//
//  H264Decoder.cpp
//  MICloudPub
//
//  Created by chenjianjun on 14-6-3.
//  Copyright (c) 2014年 hy. All rights reserved.
//

#include "H264Decoder.h"

extern "C"
{
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
#include "libavutil/opt.h"
#include "libavutil/channel_layout.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/fifo.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/avstring.h"
#include "libavutil/imgutils.h"
#include "libavfilter/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersrc.h"
#include "libavfilter/buffersink.h"
}

typedef struct
{
    struct AVCodec *codec;// Codec
    struct AVCodecContext *c;// Codec Context
    int frame_count;
    struct AVFrame *picture;// Frame
    AVPacket avpkt;
    
    int iWidth;
    int iHeight;
    int comsumedSize;
    int got_picture;
} X264_Decoder_Handle;


X264_DECODER_H H264Decoder::X264Decoder_Init()
{
    X264_Decoder_Handle *pHandle = (X264_Decoder_Handle *)malloc(sizeof(X264_Decoder_Handle));
    if (pHandle == NULL)
    {
        return -1;
    }
    
    avcodec_register_all();
    
    av_init_packet(&(pHandle->avpkt));
    
    pHandle->codec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (!pHandle->codec)
    {
        return -2;
    }
    
    pHandle->c = avcodec_alloc_context3(pHandle->codec);
    if (!pHandle->c)
    {
        return -3;
    }
    
    pHandle->c->codec_type = AVMEDIA_TYPE_VIDEO;
    pHandle->c->pix_fmt = PIX_FMT_YUV420P;
    
    if (avcodec_open2(pHandle->c, pHandle->codec, NULL) < 0)
    {
        return -4;
    }
    
    pHandle->picture = av_frame_alloc();
    if (!pHandle->picture)
    {
        return -5;
    }
    
    pHandle->frame_count = 0;
    
    return (X264_DECODER_H)pHandle;
}

void H264Decoder::X264Decoder_UnInit(X264_DECODER_H dwHandle)
{
    if (dwHandle <= 0)
    {
        return;
    }
    
    X264_Decoder_Handle *pHandle = (X264_Decoder_Handle *)dwHandle;
    
    avcodec_close(pHandle->c);
    av_free(pHandle->c);
    av_frame_free(&pHandle->picture);
    
    free(pHandle);
}

int H264Decoder::X264Decoder_Decode(X264_DECODER_H dwHandle, uint8_t *pDataIn, int nInSize, uint8_t *pDataOut, int nOutSize, int *nWidth, int *nHeight)
{
    if (dwHandle <= 0)
    {
        return -1;
    }
    
    X264_Decoder_Handle *pHandle = (X264_Decoder_Handle *)dwHandle;
    
    av_init_packet(&(pHandle->avpkt));
    pHandle->avpkt.size = nInSize;
    pHandle->avpkt.data = pDataIn;
    
    while (pHandle->avpkt.size > 0)
    {
        pHandle->comsumedSize = avcodec_decode_video2(pHandle->c, pHandle->picture, &pHandle->got_picture, &(pHandle->avpkt));
        if (pHandle->comsumedSize < 0)
        {
            return -2;
        }
        
        if (pHandle->got_picture)
        {
            *nWidth = pHandle->c->width;
            *nHeight = pHandle->c->height;
            
            pgm_save2(pHandle->picture->data[0],
                      pHandle->picture->linesize[0],
                      pHandle->c->width,
                      pHandle->c->height,pDataOut);
            pgm_save2(pHandle->picture->data[1],
                      pHandle->picture->linesize[1],
                      pHandle->c->width/2,
                      pHandle->c->height/2,
                      pDataOut +pHandle->c->width * pHandle->c->height);
            pgm_save2(pHandle->picture->data[2],
                      pHandle->picture->linesize[2],
                      pHandle->c->width/2,
                      pHandle->c->height/2,
                      pDataOut +pHandle->c->width * pHandle->c->height*5/4);
        }
        
        if (pHandle->avpkt.data)
        {
            pHandle->avpkt.size -= pHandle->comsumedSize;
            pHandle->avpkt.data += pHandle->comsumedSize;
        }
    }
    
    return 0;
}

主要給大家講講X264Decoder_Decode這個介面的引數說明:
dwHandle:其實就是我們初期化的那個結構體指標
pDataIn:是你接收到的網路資料包,這個資料包必須是完整的幀(如果一幀資料太大的話,伺服器會分包傳送,這個時候就需要客戶端快取重組),
         不然會解碼失敗,我做的過程中如果重組後的包不全,h264裡面會報很多莫名的錯誤日誌。
nInSize:接收到的網路資料包
pDataOut:解碼後的資料存放區
nOutSize:解碼後的資料存放區大小
nWidth:解碼後的視訊寬度
nHeight:解碼後的視訊高度

函式裡面有個迴圈解碼的過程,其實你可以寫成解碼一次就行了,這樣寫是考慮解碼的時候是根據naul來解碼的,有可能一幀資料有幾個naul頭。

解碼後的資料通過opengl渲染,效果還不錯。

iphone5 解碼720P的資料,每秒20到25幀的資料,cpu達到85%左右。


相關推薦

ffmpeg解碼網路rtp(包裝h264)

最近接了一個做ffmpeg解碼的專案,客戶的視訊都是在伺服器上編碼的(H264編碼),編碼後的資料通過rtp封裝傳送到客戶端,客戶端負責解碼顯示。 前期準備: 下載ffmpeg編譯ios版本 檢視ffmpeg的例子程式碼,結果發現都是基於讀檔案的例子,相信很多沒有做過的

使用 ffmpeg 進行網路:拉->解封裝->解碼->處理原始資料(音訊、視訊)->編碼->編碼->推

簡要說明: 1、可拉流:rtmp、rtsp、http 2、可推流: #include "stdafx.h" extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #

使用FFMPeg解碼顯示ts

公司最近專案不是很忙,就將之前弄東西整理了一下,解碼直播流使用FFMPeg, 之前做的一個專案是智慧家居的控制系統,加監控,這個監控有多個攝像頭,每一個都要顯示出來,並將預覽的畫面在不同的位置顯示出來,達到同步的效果,之前使用的VLC解碼顯示的,但是太多預覽源

FFMPEG 實時解碼網路H264RTP封裝

初學FFMPEG和H264,解碼視訊流時遇到了很多麻煩,記錄一下研究成果。 我使用的FFMPEG 2.5.2版本,使用av_parser_parse2重組影象幀時遇到了一下麻煩! 下面是主要程式碼: RTP頭定義, typedef struct { /**/

FFmpeg解碼H264並轉換成opencv Mat

最近要搞一些視訊推流的事情,要解析H264裸流並且獲取opencv格式的Mat資料給演算法工程師們跑演算法.相關資源一直很難找到,經常都是太舊導致API版本都更新換代了,沒辦法讓新人或者外行[比如我]快速驗證程式碼是否可行.在參考多個部落格,前人的程式碼

03 ffmpeg 解碼SDK調用 H264轉YUV420

03 ffmpeg 解碼sdk調用 h264轉yuv420制作一個H264文件[root@localhost ~]# cd /home/ [root@localhost home]# wget http://sh.yinyuetai.com/uploads/videos/common/0E3E014EBF34

FFmpeg解碼MP4檔案為h264和YUV檔案

#include <iostream> #ifdef __cplusplus extern "C" { #endif #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #in

史上最全的基於ffmpeg+sdl網路攝像頭編解碼播放資料(包含交叉編譯過程,附帶完整原始碼)

原創博文,嚴禁私自轉載,轉載請註明出處!!! 近期,由於工作需要,要在開發板上跑一個攝像頭,攝像頭款式比較老,不支援rtsp格式,所以選擇編譯ffmpeg+sdl實現軟解碼播放攝像頭,特此記錄整個編譯過程(非常之艱辛,發文留念) 在ubuntu上交叉編譯環境的搭建:因為開發板上搭建的程式的執

Live555接收h264使用ffmpeg解碼為YUV42

轉載:http://www.tuicool.com/articles/rmQ732 本文概要:                 本文介紹了一種常用成熟的多媒體解碼方案。使用live555作為流媒體資料來源,建立rtsp會話請求h264資料流。後端使用ffmpeg解碼h

使用FFmpeg轉錄網路直播

愛奇藝萬能播放器的最新版本增加了一個播放網路流的功能。不過,入口藏在播放器區域的右鍵選單裡,不太好找:找來一個直播流URL,比如東森新聞 http://60.199.188.151/HLS/WG_ETTV-N/index.m3u8,試了一下,還不賴呢!有時候,看到精彩的直播內

ffmpeg多執行緒本地mp4 rtmp推h264+aac編碼

程式說明:使用了c++11的std執行緒,鎖,訊號量等東西,替換了pthread多執行緒。主要之前用windows下移植的linux發現多執行緒始終有問題,所以決定用原生的試試。不過現在想來,應該問題還是我佇列的設計問題。主要這裡有個坑,就是c語言for迴圈內部

基於FFMPEG SDK媒體開發1---解碼媒體檔案資訊

最近專案涉及到流媒體等開發,由於有過開發經驗深知其難度所在,沒辦法只能重新拾起,最新版的SDK被改的一塌糊塗,不過大體的開發思路都是一樣的,看多少書查多少資料都無用,一步一步的編寫程式碼 才是學好的關鍵。。 我會把每一天的學習經過,更新到博文上,希望能給更多想學習的人帶來幫

Live555接收h264使用ffmpeg解碼為YUV420

本文概要:                 本文介紹了一種常用成熟的多媒體解碼方案。使用live555作為流媒體資料來源,建立rtsp會話請求h264資料流。後端使用ffmpeg解碼h264流並儲存為yuv420格式。                 該方案比較成熟,可行性

ffmpeg解碼h264檔案,opencv顯示

H264.h #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <string.h> #include <winsock2

Android FFMpeg(三)——使用FFMpeg解碼h264、aac

前面部落格記錄了FFMpeg的編譯,編譯後我們可以拿到FFMpeg的動態庫和靜態庫,拿到這些庫檔案後,通常我們需要做個簡單的封裝才能在Android上層愉快的使用。本篇部落格的是從拿到FFMpeg靜態庫到使用FFMpeg解碼視訊的過程,記錄儘可能的詳盡,可能會讓

Android使用FFmpeg 解碼H264並播放(三)

上一節記錄了Android使用FFmpeg解碼H264的過程。這一節記錄在Android上播放的過程。 問題描述 在開發中使用某攝像頭的SDK,只能獲取到一幀幀的 H264 視訊資料,不知道視訊流地址,需要自己解碼出影象並播放。 問題解決 A

Android使用FFmpeg 解碼H264並播放(二)

上一節記錄了Android使用FFmpeg環境搭建過程。這一節記錄視訊解碼過程。 問題描述 在開發中使用某攝像頭的SDK,只能獲取到一幀幀的 H264 視訊資料,不知道視訊流地址,需要自己解碼出影象並播放。 問題解決 編譯FFmpeg 點選

RTSP取+FFmpeg解碼+OpenGL顯示

該DEMO集合RTSP取流、FFmpeg解碼、OpenGL視訊顯示,自己記錄一下,也跟大家分享一下。 該DEMO參考了以下網站: 1、https://github.com/htwahzs/Rts

在iOS平臺使用ffmpeg解碼h264視訊流

對於視訊檔案和rtsp之類的主流視訊傳輸協議,ffmpeg提供avformat_open_input介面,直接將檔案路徑或URL傳入即可開啟。讀取視訊資料、解碼器初始引數設定等,都可以通過呼叫API來完成。 但是對於h264流,沒有任何封裝格式,也就無法使用libavformat。所以許多工作需要自己手工完

H.264媒體UDP組播和ffmpeg解碼實驗

簡介:將H.264視訊流從傳送端通過UDP組播到接收端,並通過ffmpeg解碼播放。 分為四步: 1 路由器端區域網下設定虛擬伺服器 2 TCP/UDP通訊測試 3 傳送端與接收端ffmpeg的安裝 4 通過指令對H264流媒體組播和解碼 第一步:區域網下設定虛擬伺服器