ffmpeg处理rtmp/文件/rtsp的推流和拉流

ffmpeg处理rtmp/文件/rtsp的推流和拉流

 
本demo演示了利用ffmpeg从服务器拉流或本地文件读取流,更改流url或文件类型名称发送回服务器或存到本地的作用。
由于本程序只写了3个小时,还要忙别的,所以会有一些bug和优化的地方。不过demo的意义已经达到了。
 
  1. //info.h
  2. #ifndef __INFO_H__
  3. #define __INFO_H__
  4. #include <string.h>
  5. #include <stdio.h>
  6. #endif
  1. //ffmpeg.h
  2. #ifndef __FFMPEG_H__
  3. #define __FFMPEG_H__
  4. #include "info.h"
  5. extern "C"
  6. {
  7. #include "libavformat/avformat.h"
  8. #include "libavformat/avio.h"
  9. #include "libavcodec/avcodec.h"
  10. #include "libswscale/swscale.h"
  11. #include "libavutil/avutil.h"
  12. #include "libavutil/mathematics.h"
  13. #include "libswresample/swresample.h"
  14. #include "libavutil/opt.h"
  15. #include "libavutil/channel_layout.h"
  16. #include "libavutil/samplefmt.h"
  17. #include "libavdevice/avdevice.h"  //摄像头所用
  18. #include "libavfilter/avfilter.h"
  19. #include "libavutil/error.h"
  20. #include "libavutil/mathematics.h"
  21. #include "libavutil/time.h"
  22. #include "inttypes.h"
  23. #include "stdint.h"
  24. };
  25. #pragma comment(lib,"avformat.lib")
  26. #pragma comment(lib,"avcodec.lib")
  27. #pragma comment(lib,"avdevice.lib")
  28. #pragma comment(lib,"avfilter.lib")
  29. #pragma comment(lib,"avutil.lib")
  30. #pragma comment(lib,"postproc.lib")
  31. #pragma comment(lib,"swresample.lib")
  32. #pragma comment(lib,"swscale.lib")
  33. //#define INPUTURL   "test.flv"
  34. #define INPUTURL     "rtmp://test1.com:1935/myapp/teststream1"
  35. //#define OUTPUTURL  "testnew.flv";
  36. #define OUTPUTURL    "rtmp://test1.com:1935/myapp/teststream1new"
  37. //video param
  38. extern int m_dwWidth;
  39. extern int m_dwHeight;
  40. extern double m_dbFrameRate;  //帧率
  41. extern AVCodecID video_codecID;
  42. extern AVPixelFormat video_pixelfromat;
  43. extern char spspps[100];
  44. extern int spspps_size;
  45. //audio param
  46. extern int m_dwChannelCount; //声道
  47. extern int m_dwBitsPerSample; //样本
  48. extern int m_dwFrequency;     //采样率
  49. extern AVCodecID audio_codecID;
  50. extern int audio_frame_size;
  51. #define AUDIO_ID            0                                                 //packet 中的ID ,如果先加入音频 pocket 则音频是 0  视频是1,否则相反
  52. #define VEDIO_ID            1
  53. extern int nRet;                                                              //状态标志
  54. extern AVFormatContext* icodec;
  55. extern AVInputFormat* ifmt;
  56. extern char szError[256];                                                     //错误字符串
  57. extern AVFormatContext* oc ;                                                  //输出流context
  58. extern AVOutputFormat* ofmt;
  59. extern AVStream* video_st;
  60. extern AVStream* audio_st;
  61. extern AVCodec *audio_codec;
  62. extern AVCodec *video_codec;
  63. extern int video_stream_idx;
  64. extern int audio_stream_idx;
  65. extern AVPacket pkt;
  66. extern AVBitStreamFilterContext * vbsf_aac_adtstoasc;                         //aac->adts to asc过滤器
  67. static int  m_nVideoTimeStamp = 0;
  68. static int  m_nAudioTimeStamp = 0;
  69. int InitInput(char * Filename,AVFormatContext ** iframe_c,AVInputFormat** iinputframe);
  70. int InitOutput();
  71. AVStream * Add_output_stream_2(AVFormatContext* output_format_context,AVMediaType codec_type_t, AVCodecID codecID,AVCodec **codec);
  72. int OpenCodec(AVStream * istream, AVCodec * icodec); //打开编解码器
  73. void read_frame(AVFormatContext *oc);    //从文件读取一帧数据根据ID读取不同的帧
  74. void write_frame_3(AVFormatContext *oc,int ID,AVPacket pkt_t); //这个是根据传过来的buf 和size 写入文件
  75. int Es2Mux_2(); //通过时间戳控制写入音视频帧顺序
  76. int UintInput();
  77. int UintOutput();
  78. #endif
 
  1. //ffmpeg.cpp
  2. #include "ffmpeg.h"
  3. int nRet = 0;
  4. AVFormatContext* icodec = NULL;
  5. AVInputFormat* ifmt = NULL;
  6. char szError[256];
  7. AVFormatContext* oc = NULL;
  8. AVOutputFormat* ofmt = NULL;
  9. AVStream * video_st = NULL;
  10. AVStream * audio_st = NULL;
  11. AVCodec *audio_codec;
  12. AVCodec *video_codec;
  13. double audio_pts = 0.0;
  14. double video_pts = 0.0;
  15. int video_stream_idx = -1;
  16. int audio_stream_idx = -1;
  17. AVPacket pkt;
  18. AVBitStreamFilterContext * vbsf_aac_adtstoasc = NULL;
  19. //video param
  20. int m_dwWidth = 0;
  21. int m_dwHeight = 0;
  22. double m_dbFrameRate = 25.0;  //帧率
  23. AVCodecID video_codecID = AV_CODEC_ID_H264;
  24. AVPixelFormat video_pixelfromat = AV_PIX_FMT_YUV420P;
  25. char spspps[100];
  26. int spspps_size = 0;
  27. //audio param
  28. int m_dwChannelCount = 2;      //声道
  29. int m_dwBitsPerSample = 16;    //样本
  30. int m_dwFrequency = 44100;     //采样率
  31. AVCodecID audio_codecID = AV_CODEC_ID_AAC;
  32. int audio_frame_size  = 1024;
  33. int InitInput(char * Filename,AVFormatContext ** iframe_c,AVInputFormat** iinputframe)
  34. {
  35. int i = 0;
  36. nRet = avformat_open_input(iframe_c, Filename,(*iinputframe), NULL);
  37. if (nRet != 0)
  38. {
  39. av_strerror(nRet, szError, 256);
  40. printf(szError);
  41. printf("\n");
  42. printf("Call avformat_open_input function failed!\n");
  43. return 0;
  44. }
  45. if (av_find_stream_info(*iframe_c) < 0)
  46. {
  47. printf("Call av_find_stream_info function failed!\n");
  48. return 0;
  49. }
  50. //输出视频信息
  51. av_dump_format(*iframe_c, -1, Filename, 0);
  52. //添加音频信息到输出context
  53. for (i = 0; i < (*iframe_c)->nb_streams; i++)
  54. {
  55. if ((*iframe_c)->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
  56. {
  57. video_stream_idx = i;
  58. m_dwWidth = (*iframe_c)->streams[i]->codec->width;
  59. m_dwHeight = (*iframe_c)->streams[i]->codec->height;
  60. m_dbFrameRate = av_q2d((*iframe_c)->streams[i]->r_frame_rate);
  61. video_codecID = (*iframe_c)->streams[i]->codec->codec_id;
  62. video_pixelfromat = (*iframe_c)->streams[i]->codec->pix_fmt;
  63. spspps_size = (*iframe_c)->streams[i]->codec->extradata_size;
  64. memcpy(spspps,(*iframe_c)->streams[i]->codec->extradata,spspps_size);
  65. }
  66. else if ((*iframe_c)->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
  67. {
  68. audio_stream_idx = i;
  69. m_dwChannelCount = (*iframe_c)->streams[i]->codec->channels;
  70. switch ((*iframe_c)->streams[i]->codec->sample_fmt)
  71. {
  72. case AV_SAMPLE_FMT_U8:
  73. m_dwBitsPerSample  = 8;
  74. break;
  75. case AV_SAMPLE_FMT_S16:
  76. m_dwBitsPerSample  = 16;
  77. break;
  78. case AV_SAMPLE_FMT_S32:
  79. m_dwBitsPerSample  = 32;
  80. break;
  81. default:
  82. break;
  83. }
  84. m_dwFrequency = (*iframe_c)->streams[i]->codec->sample_rate;
  85. audio_codecID = (*iframe_c)->streams[i]->codec->codec_id;
  86. audio_frame_size = (*iframe_c)->streams[i]->codec->frame_size;
  87. }
  88. }
  89. return 1;
  90. }
  91. int InitOutput()
  92. {
  93. int i = 0;
  94. /* allocate the output media context */
  95. avformat_alloc_output_context2(&oc, NULL, "flv", OUTPUTURL);
  96. if (!oc)
  97. {
  98. return getchar();
  99. }
  100. ofmt = oc->oformat;
  101. /* open the output file, if needed */
  102. if (!(ofmt->flags & AVFMT_NOFILE))
  103. {
  104. if (avio_open(&oc->pb, OUTPUTURL, AVIO_FLAG_WRITE) < 0)
  105. {
  106. printf("Could not open '%s'\n", OUTPUTURL);
  107. return getchar();
  108. }
  109. }
  110. //添加音频信息到输出context
  111. if(audio_stream_idx != -1)
  112. {
  113. ofmt->audio_codec = audio_codecID;
  114. audio_st = Add_output_stream_2(oc, AVMEDIA_TYPE_AUDIO,audio_codecID,&audio_codec);
  115. }
  116. //添加视频信息到输出context
  117. ofmt->video_codec = video_codecID;
  118. video_st = Add_output_stream_2(oc, AVMEDIA_TYPE_VIDEO,video_codecID,&video_codec);
  119. if (OpenCodec(video_st,video_codec) < 0)   //打开视频编码器
  120. {
  121. printf("can not open video codec\n");
  122. return getchar();
  123. }
  124. if(audio_stream_idx != -1)
  125. {
  126. if (OpenCodec(audio_st,audio_codec) < 0)   //打开音频编码器
  127. {
  128. printf("can not open audio codec\n");
  129. return getchar();
  130. }
  131. }
  132. av_dump_format(oc, 0, OUTPUTURL, 1);
  133. if (avformat_write_header(oc, NULL))
  134. {
  135. printf("Call avformat_write_header function failed.\n");
  136. return 0;
  137. }
  138. if(audio_stream_idx != -1)
  139. {
  140. if ((strstr(oc->oformat->name, "flv") != NULL) ||
  141. (strstr(oc->oformat->name, "mp4") != NULL) ||
  142. (strstr(oc->oformat->name, "mov") != NULL) ||
  143. (strstr(oc->oformat->name, "3gp") != NULL))
  144. {
  145. if (audio_st->codec->codec_id == AV_CODEC_ID_AAC) //AV_CODEC_ID_AAC
  146. {
  147. vbsf_aac_adtstoasc =  av_bitstream_filter_init("aac_adtstoasc");
  148. }
  149. }
  150. }
  151. if(vbsf_aac_adtstoasc == NULL)
  152. {
  153. return -1;
  154. }
  155. return 1;
  156. }
  157. AVStream * Add_output_stream_2(AVFormatContext* output_format_context,AVMediaType codec_type_t, AVCodecID codecID,AVCodec **codec)
  158. {
  159. AVCodecContext* output_codec_context = NULL;
  160. AVStream * output_stream = NULL;
  161. /* find the encoder */
  162. *codec = avcodec_find_encoder(codecID);
  163. if (!(*codec))
  164. {
  165. return NULL;
  166. }
  167. output_stream = avformat_new_stream(output_format_context, *codec);
  168. if (!output_stream)
  169. {
  170. return NULL;
  171. }
  172. output_stream->id = output_format_context->nb_streams - 1;
  173. output_codec_context = output_stream->codec;
  174. output_codec_context->codec_id = codecID;
  175. output_codec_context->codec_type = codec_type_t;
  176. switch (codec_type_t)
  177. {
  178. case AVMEDIA_TYPE_AUDIO:
  179. AVRational CodecContext_time_base;
  180. CodecContext_time_base.num = 1;
  181. CodecContext_time_base.den = m_dwFrequency;
  182. output_stream->time_base = CodecContext_time_base;
  183. output_codec_context->time_base = CodecContext_time_base;
  184. output_stream->start_time = 0;
  185. output_codec_context->sample_rate = m_dwFrequency;
  186. output_codec_context->channels = m_dwChannelCount;
  187. output_codec_context->frame_size = audio_frame_size;
  188. switch (m_dwBitsPerSample)
  189. {
  190. case 8:
  191. output_codec_context->sample_fmt  = AV_SAMPLE_FMT_U8;
  192. break;
  193. case 16:
  194. output_codec_context->sample_fmt  = AV_SAMPLE_FMT_S16;
  195. break;
  196. case 32:
  197. output_codec_context->sample_fmt  = AV_SAMPLE_FMT_S32;
  198. break;
  199. default:
  200. break;
  201. }
  202. output_codec_context->block_align = 0;
  203. if(! strcmp( output_format_context-> oformat-> name,  "mp4" ) ||
  204. !strcmp (output_format_context ->oformat ->name , "mov" ) ||
  205. !strcmp (output_format_context ->oformat ->name , "3gp" ) ||
  206. !strcmp (output_format_context ->oformat ->name , "flv" ))
  207. {
  208. output_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
  209. }
  210. break;
  211. case AVMEDIA_TYPE_VIDEO:
  212. AVRational r_frame_rate_t;
  213. r_frame_rate_t.num = 1000;
  214. r_frame_rate_t.den = (int)(m_dbFrameRate * 1000);
  215. output_stream->time_base = r_frame_rate_t;
  216. output_codec_context->time_base = r_frame_rate_t;
  217. AVRational r_frame_rate_s;
  218. r_frame_rate_s.num = (int)(m_dbFrameRate * 1000);
  219. r_frame_rate_s.den = 1000;
  220. output_stream->r_frame_rate = r_frame_rate_s;
  221. output_stream->start_time = 0;
  222. output_codec_context->pix_fmt = video_pixelfromat;
  223. output_codec_context->width = m_dwWidth;
  224. output_codec_context->height = m_dwHeight;
  225. output_codec_context->extradata = (uint8_t *)spspps;
  226. output_codec_context->extradata_size = spspps_size;
  227. //这里注意不要加头,demux的时候 h264filter过滤器会改变文件本身信息
  228. //这里用output_codec_context->extradata 来显示缩略图
  229. //if(! strcmp( output_format_context-> oformat-> name,  "mp4" ) ||
  230. //  !strcmp (output_format_context ->oformat ->name , "mov" ) ||
  231. //  !strcmp (output_format_context ->oformat ->name , "3gp" ) ||
  232. //  !strcmp (output_format_context ->oformat ->name , "flv" ))
  233. //{
  234. //  output_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
  235. //}
  236. break;
  237. default:
  238. break;
  239. }
  240. return output_stream;
  241. }
  242. int OpenCodec(AVStream * istream, AVCodec * icodec)
  243. {
  244. AVCodecContext *c = istream->codec;
  245. nRet = avcodec_open2(c, icodec, NULL);
  246. return nRet;
  247. }
  248. int UintInput()
  249. {
  250. /* free the stream */
  251. av_free(icodec);
  252. return 1;
  253. }
  254. int UintOutput()
  255. {
  256. int i = 0;
  257. nRet = av_write_trailer(oc);
  258. if (nRet < 0)
  259. {
  260. av_strerror(nRet, szError, 256);
  261. printf(szError);
  262. printf("\n");
  263. printf("Call av_write_trailer function failed\n");
  264. }
  265. if (vbsf_aac_adtstoasc !=NULL)
  266. {
  267. av_bitstream_filter_close(vbsf_aac_adtstoasc);
  268. vbsf_aac_adtstoasc = NULL;
  269. }
  270. av_dump_format(oc, -1, OUTPUTURL, 1);
  271. /* Free the streams. */
  272. for (i = 0; i < oc->nb_streams; i++)
  273. {
  274. av_freep(&oc->streams[i]->codec);
  275. av_freep(&oc->streams[i]);
  276. }
  277. if (!(ofmt->flags & AVFMT_NOFILE))
  278. {
  279. /* Close the output file. */
  280. avio_close(oc->pb);
  281. }
  282. av_free(oc);
  283. return 1;
  284. }
  285. void read_frame(AVFormatContext *oc)
  286. {
  287. int ret = 0;
  288. ret = av_read_frame(icodec, &pkt);
  289. if (pkt.stream_index == video_stream_idx)
  290. {
  291. write_frame_3(oc,VEDIO_ID,pkt);
  292. }
  293. else if (pkt.stream_index == audio_stream_idx)
  294. {
  295. write_frame_3(oc,AUDIO_ID,pkt);
  296. }
  297. }
  298. void write_frame_3(AVFormatContext *oc,int ID,AVPacket pkt_t)
  299. {
  300. int64_t pts = 0, dts = 0;
  301. int nRet = -1;
  302. AVRational time_base_t;
  303. time_base_t.num = 1;
  304. time_base_t.den = 1000;
  305. if(ID == VEDIO_ID)
  306. {
  307. AVPacket videopacket_t;
  308. av_init_packet(&videopacket_t);
  309. if (av_dup_packet(&videopacket_t) < 0)
  310. {
  311. av_free_packet(&videopacket_t);
  312. }
  313. videopacket_t.pts = pkt_t.pts;
  314. videopacket_t.dts = pkt_t.dts;
  315. videopacket_t.pos = 0;
  316. videopacket_t.priv = 0;
  317. videopacket_t.flags = 1;
  318. videopacket_t.convergence_duration = 0;
  319. videopacket_t.side_data_elems = 0;
  320. videopacket_t.stream_index = VEDIO_ID;
  321. videopacket_t.duration = 0;
  322. videopacket_t.data = pkt_t.data;
  323. videopacket_t.size = pkt_t.size;
  324. nRet = av_interleaved_write_frame(oc, &videopacket_t);
  325. if (nRet != 0)
  326. {
  327. printf("error av_interleaved_write_frame _ video\n");
  328. }
  329. av_free_packet(&videopacket_t);
  330. }
  331. else if(ID == AUDIO_ID)
  332. {
  333. AVPacket audiopacket_t;
  334. av_init_packet(&audiopacket_t);
  335. if (av_dup_packet(&audiopacket_t) < 0)
  336. {
  337. av_free_packet(&audiopacket_t);
  338. }
  339. audiopacket_t.pts = pkt_t.pts;
  340. audiopacket_t.dts = pkt_t.dts;
  341. audiopacket_t.pos = 0;
  342. audiopacket_t.priv = 0;
  343. audiopacket_t.flags = 1;
  344. audiopacket_t.duration = 0;
  345. audiopacket_t.convergence_duration = 0;
  346. audiopacket_t.side_data_elems = 0;
  347. audiopacket_t.stream_index = AUDIO_ID;
  348. audiopacket_t.duration = 0;
  349. audiopacket_t.data = pkt_t.data;
  350. audiopacket_t.size = pkt_t.size;
  351. //添加过滤器
  352. if(! strcmp( oc-> oformat-> name,  "mp4" ) ||
  353. !strcmp (oc ->oformat ->name , "mov" ) ||
  354. !strcmp (oc ->oformat ->name , "3gp" ) ||
  355. !strcmp (oc ->oformat ->name , "flv" ))
  356. {
  357. if (audio_st->codec->codec_id == AV_CODEC_ID_AAC)
  358. {
  359. if (vbsf_aac_adtstoasc != NULL)
  360. {
  361. AVPacket filteredPacket = audiopacket_t;
  362. int a = av_bitstream_filter_filter(vbsf_aac_adtstoasc,
  363. audio_st->codec, NULL,&filteredPacket.data, &filteredPacket.size,
  364. audiopacket_t.data, audiopacket_t.size, audiopacket_t.flags & AV_PKT_FLAG_KEY);
  365. if (a >  0)
  366. {
  367. av_free_packet(&audiopacket_t);
  368. filteredPacket.destruct = av_destruct_packet;
  369. audiopacket_t = filteredPacket;
  370. }
  371. else if (a == 0)
  372. {
  373. audiopacket_t = filteredPacket;
  374. }
  375. else if (a < 0)
  376. {
  377. fprintf(stderr, "%s failed for stream %d, codec %s",
  378. vbsf_aac_adtstoasc->filter->name,audiopacket_t.stream_index,audio_st->codec->codec ?  audio_st->codec->codec->name : "copy");
  379. av_free_packet(&audiopacket_t);
  380. }
  381. }
  382. }
  383. }
  384. nRet = av_interleaved_write_frame(oc, &audiopacket_t);
  385. if (nRet != 0)
  386. {
  387. printf("error av_interleaved_write_frame _ audio\n");
  388. }
  389. av_free_packet(&audiopacket_t);
  390. }
  391. }
  392. int Es2Mux_2()
  393. {
  394. for (;;)
  395. {
  396. read_frame(oc);
  397. }
  398. return 1;
  399. }
  1. //main.cpp
  2. #include "ffmpeg.h"
  3. int main(int argc ,char ** argv)
  4. {
  5. av_register_all();
  6. avformat_network_init();
  7. InitInput(INPUTURL,&icodec,&ifmt);
  8. InitOutput();
  9. printf("--------程序运行开始----------\n");
  10. //////////////////////////////////////////////////////////////////////////
  11. Es2Mux_2();
  12. //////////////////////////////////////////////////////////////////////////
  13. UintOutput();
  14. UintInput();
  15. printf("--------程序运行结束----------\n");
  16. printf("-------请按任意键退出---------\n");
  17. return getchar();
  18. }
上一篇:php页面相互调用的知识点


下一篇:用FFmpeg+nginx+rtmp搭建环境实现推流