使用ffmpeg推流


使用ffmpeg推流

本文主要參考來自雷霄驊的博客,使用nginx測是RTMP推流。
測試環境: ubuntu + nginx + vlc

  • 使用頭文件:
#include <libavformat/avformat.h>
#include <libavutil/mathematics.h>
#include <libavutil/time.h>
  • 輸入和輸出:
    通常我們使用ffmpeg輸入和輸出都是文件系統,現在要實現推流到nginx RTMP服務器,所以輸出路徑是一個RTMP協議URL:out_filename = "rtmp://localhost:1935/live1/553"; 同時必須調用函數 ```
    av_register_all();
    avformat_network_init();
打開網絡, 注冊av編解碼器。

```C
	//輸入(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;
	}

	int videoindex=-1;
	for(i=0; i<ifmt_ctx->nb_streams; 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", out_filename); //RTMP
	//avformat_alloc_output_context2(&ofmt_ctx, NULL, "mpegts", out_filename);//UDP

	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);
  • avio_open 函數和 avio_open2 函數
int avio_open (AVIOContext **s, const char *url, int flags);
int avio_open2 (AVIOContext **s, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary ** options);

這兩個函數的flags參數類似Linux下的open函數,它的Value是:

AVIO_FLAG_READ
AVIO_FLAG_WRITE
AVIO_FLAG_READ_WRITE

avio_xx 具體函數手冊上很詳細,用法和Linux編程類型,常用的函數還有avio_close, avio_read, avio_write等,更多...
現在,使用avio_open函數打開rtmp地址, 同時寫入文件頭:

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);
	}
}
//寫文件頭(Write file header)
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
	printf( "Error occurred when opening output URL\n");
}
  • 讀取輸入幀和寫入輸出幀到URL流上
ret = av_read_frame(ifmt_ctx, &pkt);
ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
  • 最后寫文件尾和關閉IO
av_write_trailer(ofmt_ctx);
avio_close(ofmt_ctx->pb);


免責聲明!

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



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