基于FFmpeg的推流器 (simplest ffmpeg streamer)

43 篇文章 0 订阅

基于FFmpeg的推流器 (simplest ffmpeg streamer)。推流器的作用就是将本地的视频数据推送至流媒体服务器。本文记录的推流器,可以将本地的 MOV / AVI / MKV / MP4 / FLV 等格式的媒体文件,通过流媒体协议(例如RTMP,HTTP,UDP,TCP,RTP等等)以直播流的形式推送出去。目前主要的推流器如下:TMP流媒体服务器(例如 Flash Media Server,Red5,Wowza等等),本文实现推流器后用相应的flash media server实现直播流播放

 

推流器代码如下:

 
  1.  
  2. #include <stdio.h>

  3.  
  4. #define __STDC_CONSTANT_MACROS

  5.  
  6. #ifdef _WIN32

  7. //Windows

  8. extern "C"

  9. {

  10. #include "libavformat/avformat.h"

  11. #include "libavutil/mathematics.h"

  12. #include "libavutil/time.h"

  13. };

  14. #else

  15. //Linux...

  16. #ifdef __cplusplus

  17. extern "C"

  18. {

  19. #endif

  20. #include <libavformat/avformat.h>

  21. #include <libavutil/mathematics.h>

  22. #include <libavutil/time.h>

  23. #ifdef __cplusplus

  24. };

  25. #endif

  26. #endif

  27.  
  28. int main(int argc, char* argv[])

  29. {

  30. AVOutputFormat *ofmt = NULL;

  31. //Input AVFormatContext and Output AVFormatContext

  32. AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;

  33. AVPacket pkt;

  34. const char *in_filename, *out_filename;

  35. int ret, i;

  36. int videoindex=-1;

  37. int frame_index=0;

  38. int64_t start_time=0;

  39.  
  40. in_filename = "dakongtou.mp4";//输入URL(Input file URL)

  41. //in_filename = "shanghai03_p.h264";

  42.  
  43. out_filename = "rtmp://localhost/test/livestream";//输出 URL(Output URL)[RTMP]

  44.  
  45. av_register_all();

  46. //Network

  47. avformat_network_init();

  48. //Input

  49. if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {

  50. printf( "Could not open input file.");

  51. goto end;

  52. }

  53. if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {

  54. printf( "Failed to retrieve input stream information");

  55. goto end;

  56. }

  57.  
  58. for(i=0; i<ifmt_ctx->nb_streams; i++)

  59. if(ifmt_ctx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){

  60. videoindex=i;

  61. break;

  62. }

  63.  
  64. av_dump_format(ifmt_ctx, 0, in_filename, 0);

  65.  
  66. //Output

  67.  
  68. avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_filename); //RTMP

  69. //avformat_alloc_output_context2(&ofmt_ctx, NULL, "mpegts", out_filename);//UDP

  70.  
  71. if (!ofmt_ctx) {

  72. printf( "Could not create output context\n");

  73. ret = AVERROR_UNKNOWN;

  74. goto end;

  75. }

  76. ofmt = ofmt_ctx->oformat;

  77. for (i = 0; i < ifmt_ctx->nb_streams; i++) {

  78. //Create output AVStream according to input AVStream

  79. AVStream *in_stream = ifmt_ctx->streams[i];

  80. AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);

  81. if (!out_stream) {

  82. printf( "Failed allocating output stream\n");

  83. ret = AVERROR_UNKNOWN;

  84. goto end;

  85. }

  86. //Copy the settings of AVCodecContext

  87. ret = avcodec_copy_context(out_stream->codec, in_stream->codec);

  88. if (ret < 0) {

  89. printf( "Failed to copy context from input to output stream codec context\n");

  90. goto end;

  91. }

  92. out_stream->codec->codec_tag = 0;

  93. if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)

  94. out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;

  95. }

  96. //Dump Format------------------

  97. av_dump_format(ofmt_ctx, 0, out_filename, 1);

  98. //Open output URL

  99. if (!(ofmt->flags & AVFMT_NOFILE)) {

  100. ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);

  101. if (ret < 0) {

  102. printf( "Could not open output URL '%s'", out_filename);

  103. goto end;

  104. }

  105. }

  106. //Write file header

  107. ret = avformat_write_header(ofmt_ctx, NULL);

  108. if (ret < 0) {

  109. printf( "Error occurred when opening output URL\n");

  110. goto end;

  111. }

  112.  
  113. start_time=av_gettime();

  114. while (1) {

  115. AVStream *in_stream, *out_stream;

  116. //Get an AVPacket

  117. ret = av_read_frame(ifmt_ctx, &pkt);

  118. if (ret < 0)

  119. break;

  120. //FIX:No PTS (Example: Raw H.264)

  121. //Simple Write PTS

  122. if(pkt.pts==AV_NOPTS_VALUE){

  123. //Write PTS

  124. AVRational time_base1=ifmt_ctx->streams[videoindex]->time_base;

  125. //Duration between 2 frames (us)

  126. int64_t calc_duration=(double)AV_TIME_BASE/av_q2d(ifmt_ctx->streams[videoindex]->r_frame_rate);

  127. //Parameters

  128. pkt.pts=(double)(frame_index*calc_duration)/(double)(av_q2d(time_base1)*AV_TIME_BASE);

  129. pkt.dts=pkt.pts;

  130. pkt.duration=(double)calc_duration/(double)(av_q2d(time_base1)*AV_TIME_BASE);

  131. }

  132. //Important:Delay

  133. if(pkt.stream_index==videoindex){

  134. AVRational time_base=ifmt_ctx->streams[videoindex]->time_base;

  135. AVRational time_base_q={1,AV_TIME_BASE};

  136. int64_t pts_time = av_rescale_q(pkt.dts, time_base, time_base_q);

  137. int64_t now_time = av_gettime() - start_time;

  138. if (pts_time > now_time)

  139. av_usleep(pts_time - now_time);

  140.  
  141. }

  142.  
  143. in_stream = ifmt_ctx->streams[pkt.stream_index];

  144. out_stream = ofmt_ctx->streams[pkt.stream_index];

  145. /* copy packet */

  146. //Convert PTS/DTS

  147. pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));

  148. pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));

  149. pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);

  150. pkt.pos = -1;

  151. //Print to Screen

  152. if(pkt.stream_index==videoindex){

  153. printf("Send %8d video frames to output URL\n",frame_index);

  154. frame_index++;

  155. }

  156. //ret = av_write_frame(ofmt_ctx, &pkt);

  157. ret = av_interleaved_write_frame(ofmt_ctx, &pkt);

  158.  
  159. if (ret < 0) {

  160. printf( "Error muxing packet\n");

  161. break;

  162. }

  163.  
  164. av_free_packet(&pkt);

  165.  
  166. }

  167. //Write file trailer

  168. av_write_trailer(ofmt_ctx);

  169. end:

  170. avformat_close_input(&ifmt_ctx);

  171. /* close output */

  172. if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))

  173. avio_close(ofmt_ctx->pb);

  174. avformat_free_context(ofmt_ctx);

  175. if (ret < 0 && ret != AVERROR_EOF) {

  176. printf( "Error occurred.\n");

  177. return -1;

  178. }

  179. return 0;

  180. }

由代码中可以看出,视频源为dakongtou.mp4,推送出的url地址为rtmp://localhost/test/livestream

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值