1. 程式人生 > >FFmpeg-rtmp推流例子(著重解析函式,剖析FFmpeg流程)

FFmpeg-rtmp推流例子(著重解析函式,剖析FFmpeg流程)

致敬雷霄驊師兄,感謝他的引領入門,以下都是他的筆記的個人補充。

本文,記錄在根據雷霄驊的RTMP推流demo原始碼,學習FFmpeg的執行流程。

記錄如下:

1. 首先是記錄demo並做一點修改,同時推送audio和video至rtmp-server。

2.對此程式碼的關鍵函式執行流程進行分析,或者說是關鍵結構體的賦值與複製的執行過程。

3.rtmp推流的簡單流程圖

rtmp-demo程式碼

#include <stdio.h>  
#include <libavformat/avformat.h>  
#include <libavutil/mathematics.h>  
#include <libavutil/time.h> 
#include <libavcodec/avcodec.h>

int main(int argc, char* argv[])  

{  
        AVOutputFormat *ofmt = NULL;  
        //輸入對應一個AVFormatContext,輸出對應一個AVFormatContext  
        //(Input AVFormatContext and Output AVFormatContext)  
        AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;  
        AVPacket pkt,pkt1;  
        const char *in_filename, *out_filename;  
        int ret, i;  
        int videoindex=-1;
        int audioindex=-1;  
        int frame_index=0;  
        int64_t start_time=0;  
        in_filename  = "test.h264";//輸入URL(Input file URL)                                                
        out_filename = "rtmp://192.168.1.190/live/livestream";//輸出 URL(Output URL)[RTMP]  

        av_register_all();	
        //Network  
        avformat_network_init();  

        //輸入(Input)  
        if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {  
            printf( "Could not open input file.");  
            goto end;  
        }  

        if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {  
            printf( "Failed to retrieve input stream information");  
            goto end;  
        }  
                                                              
        for(i=0; i<ifmt_ctx->nb_streams; i++){   
            if(ifmt_ctx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO){  
                audioindex=i;  
            }

            if(ifmt_ctx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){
                videoindex = i;
                break;}
	}
                                                                  
            av_dump_format(ifmt_ctx, 0, in_filename, 0);                                                                      
            //輸出(Output)  
                                                                         
            avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", NULL); //RTMP  
            //avformat_alloc_output_context2(&ofmt_ctx, NULL, "rtp", NULL);// RTP/RTCP於UDP傳輸,VLC播放需要SDP檔案 
            printf("filename0: %s\n",ofmt_ctx->filename );
            if (!ofmt_ctx) {  
                printf( "Could not create output context\n");  
                ret = AVERROR_UNKNOWN;  
                goto end;  
            }  

            ofmt = ofmt_ctx->oformat;  
            for (i = 0; i < ifmt_ctx->nb_streams; i++) {  
                //根據輸入流建立輸出流(Create output AVStream according to input AVStream)  
                AVStream *in_stream = ifmt_ctx->streams[i];  
                AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);  
                if (!out_stream) {  
                    printf( "Failed allocating output stream\n");  
                    ret = AVERROR_UNKNOWN;  
                    goto end;  
                }    

                //複製AVCodecContext的設定(Copy the settings of AVCodecContext)  
                ret = avcodec_copy_context(out_stream->codec, in_stream->codec);  
                if (ret < 0) {  
                    printf( "Failed to copy context from input to output stream codec context\n");  
                    goto end;  
                }  

                out_stream->codec->codec_tag = 0;  
                if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)  
                    out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;  
            }  

            //Dump Format------------------  
            av_dump_format(ofmt_ctx, 0, out_filename, 1);  


            //開啟輸出URL(Open output URL)  
            if (!(ofmt->flags & AVFMT_NOFILE)) {  
                ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);  
                if (ret < 0) {  
                    printf( "Could not open output URL '%s'", out_filename);  
                    goto end;  
                }
            }  
         
        //寫檔案頭(Write file header)  
        ret= avformat_write_header(ofmt_ctx, NULL);  
        if (ret < 0) {  
            printf( "Error occurred when opening output URL\n");  
            goto end;  
        } 
                                                                                                  
        start_time=av_gettime();  
	//av_new_packet(&pkt,2000);

        while (1) {  
            AVStream *in_stream, *out_stream;  
            //av_packet_ref(&pkt,&pkt1);
	    //獲取一個AVPacket(Get an AVPacket)
            ret = av_read_frame(ifmt_ctx, &pkt);
            if (ret < 0)  
                break;  

            //Simple Write PTS  
            if(pkt.pts==AV_NOPTS_VALUE){  
                //Write PTS  
                AVRational time_base1=ifmt_ctx->streams[videoindex]->time_base;  
                //Duration between 2 frames (us)  
                int64_t calc_duration=(double)AV_TIME_BASE/av_q2d(ifmt_ctx->streams[videoindex]->r_frame_rate);  
                //Parameters  
                pkt.pts=(double)(frame_index*calc_duration)/(double)(av_q2d(time_base1)*AV_TIME_BASE);  
                pkt.dts=pkt.pts;  
                pkt.duration=(double)calc_duration/(double)(av_q2d(time_base1)*AV_TIME_BASE);  
            }  

            //Important:Delay  
            if(pkt.stream_index==videoindex){
                AVRational time_base=ifmt_ctx->streams[videoindex]->time_base;
                AVRational time_base_q={1,AV_TIME_BASE};  
                int64_t pts_time = av_rescale_q(pkt.dts, time_base, time_base_q);  
                int64_t now_time = av_gettime() - start_time;  
                if (pts_time > now_time)  
                    av_usleep(pts_time - now_time);  
            }  

            in_stream  = ifmt_ctx->streams[pkt.stream_index];
            out_stream = ofmt_ctx->streams[pkt.stream_index]; 	
            /* copy packet */  

            //轉換PTS/DTS(Convert PTS/DTS)  
            pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, 
                                        (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));  
            pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, 
                                        (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));  
            pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);

            pkt.pos = -1; 
      
            //Print to Screen  
            if(pkt.stream_index==videoindex){  
                printf("Send %8d video frames to output URL\n",frame_index);  
                frame_index++;  
            }

            ret = av_write_frame(ofmt_ctx, &pkt);  
            //ret = av_interleaved_write_frame(ofmt_ctx, &pkt);  
            if (ret < 0){
                printf( "Error muxing packet\n");  
                break;  
            }  

            av_free_packet(&pkt);
	    //av_packet_unref(&pkt1);	
        }

        //寫檔案尾(Write file trailer)                                                        
        av_write_trailer(ofmt_ctx); 
      
end:  
        avformat_close_input(&ifmt_ctx);  
        /* close output */  
        if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))  
            avio_close(ofmt_ctx->pb);  
            avformat_free_context(ofmt_ctx);  
            if (ret < 0 && ret != AVERROR_EOF) {  
                printf( "Error occurred.\n");  
                return -1;  
            }  
        return 0;  
}  


av_register_all()

函式作用:

參考連結:

avformat_network_init()

函式作用:

參考連結:

avformat_open_input

函式作用:

參考連結:

av_dump_format

函式作用:

參考連結:

avformat_alloc_output_context2

函式作用:

參考連結:

avformat_new_stream

函式作用:

參考連結:

avcodec_copy_context

函式作用:

參考連結:

avio_open

函式作用:

參考連結:

avformat_write_header

函式作用:

參考連結:

av_gettime

函式作用:

參考連結:

av_read_frame

函式作用:

參考連結:

av_interleaved_write_frame

函式作用:

參考連結:

av_write_trailer

函式作用:

參考連結:


rtmp推流的簡單流程圖

相關推薦

FFmpeg-rtmp例子著重解析函式剖析FFmpeg流程

致敬雷霄驊師兄,感謝他的引領入門,以下都是他的筆記的個人補充。 本文,記錄在根據雷霄驊的RTMP推流demo原始碼,學習FFmpeg的執行流程。 記錄如下: 1. 首先是記錄demo並做一點修改,同時推送audio和video至rtmp-server。 2.對此程式碼的關鍵

最簡單的基於FFmpegRTMP為例

由於工作一部分工作是作為流媒體伺服器的程式設計師。所以自己那塊也算是處理了推流器的一塊程式碼吧。 這邊是從網上轉載的文章,原文:http://blog.csdn.net/leixiaohua1020/article/details/46890487 =========

ffmpeg rtmp nginx搭建的rtmp伺服器

1、利用nginx搭建的rtmp伺服器 下載nginx-rtmp-module模組,解壓 下載nginx,解壓 進入nginx目錄下,編譯安裝nginx支援rtmp流媒體配置 ./configure

FFMPEG RTMP分析

簡介 RTMP推流器(Streamer)的在流媒體系統中的作用可以用下圖表示。首先將視訊資料以RTMP的形式傳送到流媒體伺服器端(Server,比如FMS,Red5,Wowza等),然後客戶端(一般為Flash Player)通過訪問流媒體伺服器就可以收看實時流了。

第七章——Windows核心基礎-核心理論基礎0環通訊核心函式驅動載入流程

windowsR3與R0通訊         當我們呼叫某個API的時候,這個API是被封裝在某個DLL庫中,而DLL庫中的函式則是在更底層的ntdll.dll檔案中,而相對應的則是呼叫ntdll中的Native API函式ntdll中的

C++模板類內友元友元函式友元類宣告的三種情況

根據《C++ Primer》第三版16.4節的敘述,C++類模板友元分為以下幾種情況1.非模板友元類或友元函式。 書上給了一個例子:class Foo{    void bar();};template <class T>class QueueItem{   

Nginx-RTMPvideo

Camera 採集資料 Camera負責採集資料,把採集來的資料交給 X264進行編碼打包給RTMP進行推流, Camera採集來的資料是NV21, 而X264編碼的輸入資料格式為I420格式。 NV21和I420都是屬於YUV420格式。而NV21是一種two-plane模式,即Y和UV分為兩個Pla

Nginx-RTMPaudio

需要文中完整程式碼的可以前往Github上獲取,順便給個star唄。 AAC編碼 ​ 推送音訊跟推送視訊差不多,經過資料採集,編碼,然後通過RTMP推流。資料採集通常有兩種方式,一種是Java層的AudioRecord,另一種是native層opensl es;採集完後就是編碼,相比視訊比較簡單,編碼庫這

ffmpeg多執行緒本地mp4 rtmph264+aac編碼

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

ffmpeg-設定使用的協議型別TCP/UDP

如有錯誤,請指正,謝謝。 拉流(設定TCP/UDP) //設定引數 AVDictionary *format_opts = NULL; av_dict_set(&format_opts, "stimeout", std::to_string( 2* 1000000).c_

java封裝FFmpeg命令支援原生ffmpeg全部命令實現FFmpeg多程序處理與多執行緒輸出控制(開啟、關閉、查詢)rtsp/rtmp、拉

前言: 之前已經對FFmpeg命令進行了封裝http://blog.csdn.net/eguid_1/article/details/51787646,但是當時沒有考慮到擴充套件性,所以總體設計不是太好,需要改動的地方也比較多,也不支援原生ffmpeg命令,所以本次版本推翻

FFmpeg RTMPHEVC/H265

    直播流媒體協議中,HLS和RTMP協議是兩大主流協議。而眾所周知的原因,RTMP在許多年前就已經停止拓展和更新,因此標準一直無法支援HEVC的編碼格式。目前國內的CDN還有金山雲等已經對RTMP進行了標準擴充套件,播放器上ijkplayer也擴充套件了該修改。  

使用ffmpeg迴圈(迴圈讀取視訊檔案)送EasyDSS RTMP媒體伺服器的方法

需求 在做EasyDSS開發時,總是在測試推流效果。 有時候,我們想使用OBS進行推流測試,也可以,這很好。 以及其他RTMP推流工具。 但是,別忘了,還有ffmpeg這個神器。ffmpeg可以獲取各種視訊流,並推送給EasyDSS RTMP流媒體伺

視訊監控安防平臺-國標GB28181轉RTSP和RTMP進行H5(RTMP/HLS)直播支援GB28181-2016版本、支援公網碼傳輸

          視訊監控安防平臺-國標GB28181轉RTSP、RTMP和HLS管理平臺(支援GB28181-2016版本、支援公網碼流傳輸)       最近抽了點時間把國標GB28181轉RTSP、RTMP和HLS管理平臺做了簡單的整理,把相應的Demo也整理好了,

Docker安裝Red5進行rtmp

red5 detail 啟動 推流 .net tail style 安裝 dai 1、pull鏡像 docker pull mondain/red5 2、啟動原版red5 docker run --name red5 -d -p 5080:5080 -p 1935:19

使用ffmpeg 測試rtmp和拉

記錄簡單使用ffmpeg的使用: 環境:ubuntu16.04 推流操作: ffmpeg -f x11grab -i :0.0+0,0 -s 640x480 -r 10 -vcodec libx264 -preset ultrafast -acodec libmp3la

SRS服務器搭建,ffmpeg 本地

wiki config amp run 參考 figure with oot eos 參考: https://github.com/ossrs/srs/wiki/v2_CN_SampleFFMPEG git clone https://github.com/o

Android Studio 第六十期 - Android直播鬥魚部分頁面功能

直播 鬥魚 推流 代碼已經整理好,效果如下圖: 地址:https://github.com/geeklx/myapplication2018/tree/master/p004_livedemo Android Studio 第六十期 - Android推流直播(鬥魚部分頁面功能)

android全平臺編譯ffmpeg視訊實踐

ffmpeg實踐學習 android全平臺編譯ffmpeg以及x264與fdk-aac實踐 ubuntu下使用nginx和nginx-rtmp-module配置直播推流伺服器 android全平臺編譯ffmpeg合併為單個庫實踐 android-studio

基於c++實現RTSP/RTMP元件PushStream簡介

技術在於交流、溝通,轉載請註明出處並保持作品的完整性。 原文:https://blog.csdn.net/hiwubihe/article/details/84639975  [本系列相關文章]   本篇介紹一個基於C++開發的RTSP/RTMP推流元件Pus