原文出自http://blog.csdn.net/zxwangyun/article/details/8190638#reply   作者 Sloan

这里在录制时,并没有进行转码,只是相当于把rtsp视频直接保存到一个文件中。

  1. #include <stdio.h>
  2. #ifdef __cplusplus
  3. extern "C" {
  4. #endif
  5. #include <libavcodec/avcodec.h>
  6. #include <libavformat/avformat.h>
  7. //#include <libswscale/swscale.h>
  8. #ifdef _MSC_VER
  9. int strcasecmp(const char *s1, const char *s2)
  10. {
  11. while ((*s1 != '\0')
  12. && (tolower(*(unsigned char *) s1) ==
  13. tolower(*(unsigned char *) s2)))
  14. {
  15. s1++;
  16. s2++;
  17. }
  18. return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
  19. }
  20. int strncasecmp(const char *s1, const char *s2, unsigned int n)
  21. {
  22. if (n == 0)
  23. return 0;
  24. while ((n-- != 0)
  25. && (tolower(*(unsigned char *) s1) ==
  26. tolower(*(unsigned char *) s2))) {
  27. if (n == 0 || *s1 == '\0' || *s2 == '\0')
  28. return 0;
  29. s1++;
  30. s2++;
  31. }
  32. return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
  33. }
  34. #endif //_MSC_VER
  35. #ifdef __cplusplus
  36. }
  37. #endif
  38. /***********************************************************
  39. '** stream_component_open
  40. *   Description:
  41. *            //open the stream component for video/audio
  42. *
  43. *
  44. *   Params:ic-pointer which contains the url and codec details
  45. :stream_index-index denoting video or audio stream
  46. ***********************************************************/
  47. int stream_component_open(AVFormatContext *ic, int stream_index)
  48. {
  49. AVCodecContext *enc;
  50. AVCodec *codec;
  51. if (stream_index < 0 || stream_index >= (int)ic->nb_streams)
  52. return -1;
  53. enc = ic->streams[stream_index]->codec;
  54. /* prepare audio output */
  55. if (enc->codec_type == CODEC_TYPE_AUDIO)
  56. {
  57. if (enc->channels > 0)
  58. enc->request_channels = FFMIN(2, enc->channels);
  59. else
  60. enc->request_channels = 2;
  61. /*Hardcoding the codec id to PCM_MULAW if the audio
  62. codec id returned by the lib is CODEC_ID_NONE */
  63. if(enc->codec_id == CODEC_ID_NONE)
  64. {
  65. enc->codec_id = CODEC_ID_PCM_MULAW;
  66. enc->channels = 1;
  67. enc->sample_rate = 16000;
  68. enc->bit_rate = 128;
  69. }
  70. }
  71. codec = avcodec_find_decoder(enc->codec_id);
  72. enc->idct_algo           = FF_IDCT_AUTO;
  73. enc->flags2   |= CODEC_FLAG2_FAST;
  74. enc->skip_frame          = AVDISCARD_DEFAULT;
  75. enc->skip_idct           = AVDISCARD_DEFAULT;
  76. enc->skip_loop_filter    = AVDISCARD_DEFAULT;
  77. enc->error_concealment   = 3;
  78. if (!codec || avcodec_open(enc, codec) < 0)
  79. return -1;
  80. avcodec_thread_init(enc, 1);
  81. enc->thread_count= 1;
  82. ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
  83. return 0;
  84. }
  85. //声明函数
  86. int enable_local_record(AVFormatContext *ic/*已经打开的视频文件上下文*/,
  87. int videostream,int audiostream,
  88. AVFormatContext **out_oc,const char * ofile,const char * ofileformat);
  89. int exit_onerr(const char * err_desc/*错误描述*/,int err_code/*错误码*/)
  90. {
  91. printf("%s\n",err_desc);
  92. system("pause");//暂停,查看错误描述
  93. return err_code;
  94. }
  95. int main(int argc, char* argv[])
  96. {
  97. //初始化ffmpeg链表结构
  98. avcodec_register_all();                     // Register all formats and codecs
  99. av_register_all();
  100. AVPacket  packet;
  101. //打开文件
  102. AVFormatContext * ic = NULL;
  103. const char * rtsp_url = "rtsp://192.168.0.168:8557/PSIA/Streaming/channels/2?videoCodecType=H.264";
  104. if(av_open_input_file(&ic, rtsp_url, NULL, 0, NULL)!=0)
  105. {
  106. return exit_onerr("can't open file.",-1);
  107. }
  108. if(!ic)
  109. {
  110. return exit_onerr("unknow error.",-2);
  111. }
  112. ic ->max_analyze_duration = 1000;
  113. //get streams information
  114. if(av_find_stream_info(ic)<0)
  115. {
  116. av_close_input_file(ic);//退出前,记得释放资源
  117. ic = NULL;
  118. return exit_onerr("con't init streams information.",-3);
  119. }
  120. //find stream
  121. int videoStream=-1; // Didn't find a video stream
  122. int audioStream=-1; // Didn't find a audio stream
  123. // Find the first video stream
  124. for(int i=0; i<ic ->nb_streams; i++)
  125. {
  126. if( ic ->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)
  127. {
  128. videoStream=i;
  129. break;
  130. }
  131. }
  132. // Find the first audio stream
  133. for(int i=0; i<ic ->nb_streams; i++)
  134. {
  135. if( ic ->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO)
  136. {
  137. audioStream=i;
  138. break;
  139. }
  140. }
  141. //判断视频文件中是否包含音视频流,如果没有,退出
  142. if(audioStream<0 && videoStream<0)
  143. {
  144. av_close_input_file(ic);//退出前,记得释放资源
  145. ic = NULL;
  146. return exit_onerr("con't find a audio stream or video stream",-4);
  147. }
  148. //open the stream component for video
  149. int videoComponent = -1;
  150. if(videoStream >= 0)
  151. {
  152. videoComponent = stream_component_open(ic, videoStream);
  153. if(videoComponent<0)
  154. {
  155. av_close_input_file(ic);//退出前,记得释放资源
  156. return exit_onerr("not supported video stream",-5);//要求重新编译ffmpeg以支持该种编码格式
  157. }
  158. }
  159. //open the stream component for audio
  160. int audioComponent = -1;
  161. if(audioStream >= 0)
  162. {
  163. audioComponent = stream_component_open(ic, audioStream);
  164. if(audioComponent<0)
  165. {
  166. av_close_input_file(ic);//退出前,记得释放资源
  167. return exit_onerr("not supported audio stream",-6);//要求重新编译ffmpeg以支持该种编码格式
  168. }
  169. }
  170. //////////////////////////////////////////////////////
  171. int ret = 0;
  172. //初始化并打开录像
  173. AVFormatContext * oc = NULL;
  174. const char * out_file_name = "D:\\test.avi";
  175. //获取一帧完整的图像用于初始化ffmpeg内部的一些结构体数据(这里使用什么数据尚未清楚,请自行查看),否则会出现写文件头失败
  176. int got_picture = 0;
  177. AVFrame *frame = avcodec_alloc_frame();
  178. while( 1 )
  179. {
  180. if(av_read_frame( ic, &packet)<0)
  181. {
  182. av_free_packet(&packet);
  183. av_close_input_file(ic);//退出前,记得释放资源
  184. return exit_onerr("read frame error.",-7);//读取视频帧失败
  185. }
  186. if(packet.stream_index == videoStream)
  187. {
  188. avcodec_decode_video(ic->streams[videoStream]->codec, frame, &got_picture, packet.data, packet.size);
  189. }
  190. av_free_packet(&packet);
  191. if(got_picture)
  192. break;
  193. }
  194. av_free(frame);
  195. ret = enable_local_record(ic,videoStream,audioStream,&oc,out_file_name,"avi");
  196. if(ret <0 || !oc)
  197. {
  198. //退出前,记得释放资源,现在又多了个oc参数需要释放
  199. if(oc)
  200. {
  201. ///cleanup the output contents format
  202. for(unsigned int i=0;i< oc->nb_streams;i++)
  203. {
  204. av_metadata_free(&oc ->streams[i]->metadata);
  205. av_free(oc ->streams[i]->codec);
  206. av_free(oc ->streams[i]);
  207. }
  208. for(unsigned int i=0;i<oc ->nb_programs;i++)
  209. {
  210. av_metadata_free(&oc ->programs[i]->metadata);
  211. }
  212. for(unsigned int i=0;i<oc ->nb_chapters;i++)
  213. {
  214. av_metadata_free(&oc ->chapters[i]->metadata);
  215. }
  216. av_metadata_free(&oc ->metadata);
  217. av_free(oc);
  218. }
  219. av_close_input_file(ic);
  220. return exit_onerr("can't init out file.",-8);
  221. }
  222. //开始录像
  223. int video_dts = 0,audio_dts = 0;//时间戳
  224. int total_frame = 300;//写300帧文件
  225. while(total_frame--)
  226. {
  227. if( av_read_frame( ic, &packet) <0 )     //read the packet
  228. {
  229. //读取数据出错
  230. av_free_packet(&packet);
  231. break;
  232. }
  233. if(packet.data && (packet.stream_index == videoStream || packet.stream_index == audioStream) )
  234. {
  235. //计算时间视频戳,顺序+1,这里可以多研究几种编码的音视频文件,求其时间戳生成格式,h264编码顺序加1即可
  236. if(packet.stream_index == videoStream)
  237. {
  238. packet.dts = video_dts++;
  239. packet.pts = video_dts;
  240. }
  241. else if(packet.stream_index == audioStream)//计算音频时间戳
  242. {
  243. packet.dts = audio_dts++;
  244. packet.pts = audio_dts * (1000 * packet.size /ic ->streams[packet.stream_index]->codec ->sample_rate);
  245. }
  246. packet.flags |= PKT_FLAG_KEY;
  247. if(av_interleaved_write_frame(oc,&packet)<0)
  248. {
  249. printf("st:%d\twrite frame failed.\n",packet.stream_index);
  250. }
  251. }
  252. av_free_packet(&packet);
  253. }
  254. //关闭录像文件和输入文件
  255. //写文件尾
  256. av_write_trailer(oc);
  257. /* close the output file if need.*/
  258. if (!(oc ->oformat->flags & AVFMT_NOFILE))
  259. {
  260. url_fclose(oc->pb);
  261. }
  262. //释放资源
  263. /*cleanup the output contents format*/
  264. for(unsigned int i=0;i< oc->nb_streams;i++)
  265. {
  266. av_metadata_free(&oc ->streams[i]->metadata);
  267. av_free(oc ->streams[i]->codec);
  268. av_free(oc ->streams[i]);
  269. }
  270. for(unsigned int i=0;i<oc ->nb_programs;i++)
  271. {
  272. av_metadata_free(&oc ->programs[i]->metadata);
  273. }
  274. for(unsigned int i=0;i<oc ->nb_chapters;i++)
  275. {
  276. av_metadata_free(&oc ->chapters[i]->metadata);
  277. }
  278. av_metadata_free(&oc ->metadata);
  279. av_free(oc);
  280. av_close_input_file(ic);
  281. return 0;
  282. }
  283. //初始化录像文件,代码较长,可写成函数
  284. /*
  285. *return <0  failed, 0 success
  286. */
  287. int enable_local_record(AVFormatContext *ic/*已经打开的视频文件上下文*/,int videostream,int audiostream,AVFormatContext **out_oc,const char * ofile,const char * ofileformat)
  288. {
  289. AVFormatContext *oc     = NULL;//
  290. AVOutputFormat  *fmt    = NULL;
  291. if( ofileformat )
  292. {
  293. fmt = av_guess_format(ofileformat, NULL, NULL);
  294. }
  295. if(!fmt)
  296. {
  297. printf("out file format \"%s\" invalidate.\n",ofileformat);
  298. return -1;
  299. }
  300. /*******************************************init output contents begin**********************************************************/
  301. /* allocate the output media context */
  302. oc = avformat_alloc_context();
  303. if (!oc)
  304. {
  305. printf("out of memory.\n");
  306. return -2;//内存分配失败
  307. }
  308. *out_oc = oc;
  309. oc ->oformat = fmt;
  310. sprintf_s( oc ->filename, sizeof( oc ->filename), "%s", ofile);
  311. av_metadata_conv(oc, fmt->metadata_conv, NULL);
  312. if( videostream >=0 )
  313. {
  314. //AVCodecContext* pCodecCtx= ->streams[videostream]->codec;;
  315. //add video stream
  316. AVStream * st = av_new_stream(oc, videostream);
  317. if(!st)
  318. {
  319. printf("can not add a video stream.\n");
  320. return -3;
  321. }
  322. st->codec->codec_id           =  ic ->streams[videostream] ->codec->codec_id;
  323. st->codec->codec_type     =  CODEC_TYPE_VIDEO;
  324. st->codec->bit_rate           =  ic ->streams[videostream] ->codec->bit_rate;
  325. st->codec->width          =  ic ->streams[videostream] ->codec->width;
  326. st->codec->height         =  ic ->streams[videostream] ->codec->height;
  327. st->codec->gop_size           =  ic ->streams[videostream] ->codec->gop_size;
  328. st->codec->pix_fmt            =  ic ->streams[videostream] ->codec->pix_fmt;
  329. st->codec->frame_size     =  ic ->streams[videostream] ->codec->frame_size;
  330. st->codec->has_b_frames       =  ic ->streams[videostream] ->codec->has_b_frames;
  331. st->codec->extradata      =  ic ->streams[videostream] ->codec->extradata;
  332. st->codec->extradata_size =  ic ->streams[videostream] ->codec->extradata_size;
  333. st->codec->codec_tag      =  ic ->streams[videostream] ->codec->codec_tag;
  334. st->codec->bits_per_raw_sample        =  ic ->streams[videostream] ->codec->bits_per_raw_sample;
  335. st->codec->chroma_sample_location =  ic ->streams[videostream] ->codec->chroma_sample_location;
  336. st->time_base.den            =  ic ->streams[videostream] ->time_base.den;
  337. st->time_base.num            =  ic ->streams[videostream] ->time_base.num;
  338. st->cur_dts                  =  ic ->streams[videostream] ->cur_dts;
  339. st->stream_copy              =  1;
  340. st->pts.den                  =  ic ->streams[videostream] ->time_base.den;
  341. st->pts.num                  =  ic ->streams[videostream] ->time_base.num;
  342. if( oc ->oformat->flags & AVFMT_GLOBALHEADER)
  343. st ->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
  344. if(av_q2d(ic ->streams[videostream] ->codec->time_base)*ic ->streams[videostream] ->codec->ticks_per_frame > av_q2d(ic ->streams[videostream]->time_base) &&
  345. av_q2d(ic ->streams[videostream]->time_base) < 1.0/1000)
  346. {
  347. st->codec->time_base = ic ->streams[videostream] ->codec->time_base;
  348. st->codec->time_base.num *= ic ->streams[videostream] ->codec->ticks_per_frame;
  349. }
  350. else
  351. {
  352. st->codec->time_base = ic ->streams[videostream] ->time_base;
  353. }
  354. st->disposition              =  ic ->streams[videostream] ->disposition;
  355. }
  356. if(audiostream >= 0 )
  357. {
  358. AVStream * st = av_new_stream( oc, audiostream);
  359. if(!st)
  360. {
  361. printf("can not add a audio stream.\n");
  362. return -4;
  363. }
  364. st->codec->codec_id           =  ic ->streams[audiostream] ->codec->codec_id;
  365. st->codec->codec_type     =  CODEC_TYPE_AUDIO;
  366. st->codec->bit_rate           =  ic ->streams[audiostream] ->codec->bit_rate;
  367. st->codec->gop_size           =  ic ->streams[audiostream] ->codec->gop_size;
  368. st->codec->pix_fmt            =  ic ->streams[audiostream] ->codec->pix_fmt;
  369. st->codec->bit_rate           =  ic ->streams[audiostream] ->codec->bit_rate;
  370. st->codec->channel_layout =  ic ->streams[audiostream] ->codec->channel_layout;
  371. st->codec->frame_size     =  ic ->streams[audiostream] ->codec->frame_size;
  372. st->codec->sample_rate        =  ic ->streams[audiostream] ->codec->sample_rate;
  373. st->codec->channels           =  ic ->streams[audiostream] ->codec->channels;
  374. st->codec->block_align        =  ic ->streams[audiostream] ->codec->block_align;
  375. st->time_base.den            =  ic ->streams[audiostream] ->time_base.den;
  376. st->time_base.num            =  ic ->streams[audiostream] ->time_base.num;
  377. st->stream_copy              =  1;
  378. st->pts.den                  =  ic ->streams[audiostream] ->time_base.den;
  379. st->pts.num                  =  ic ->streams[audiostream] ->time_base.num;
  380. if( oc->oformat->flags & AVFMT_GLOBALHEADER)
  381. st ->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
  382. if(av_q2d(ic ->streams[audiostream] ->codec->time_base)*ic ->streams[audiostream] ->codec->ticks_per_frame > av_q2d(ic ->streams[audiostream]->time_base) &&
  383. av_q2d(ic ->streams[audiostream]->time_base) < 1.0/1000)
  384. {
  385. st->codec->time_base = ic ->streams[audiostream] ->codec->time_base;
  386. st->codec->time_base.num *= ic ->streams[audiostream] ->codec->ticks_per_frame;
  387. }
  388. else
  389. {
  390. st->codec->time_base = ic ->streams[audiostream] ->time_base;
  391. }
  392. }
  393. /* set the output parameters (must be done even if no parameters). */
  394. //AVFormatParameters params, *ap = ¶ms;
  395. //memset(ap, 0, sizeof(*ap));
  396. if (av_set_parameters(oc, NULL/*ap*/) < 0)
  397. {
  398. printf("invalid output format parameters.\n");
  399. return -5;
  400. }
  401. oc ->flags |= AVFMT_FLAG_NONBLOCK;
  402. /*******************************************init output contents end**********************************************************/
  403. /* open the output file, if needed */
  404. if (!(oc ->oformat ->flags & AVFMT_NOFILE))
  405. {
  406. try
  407. {
  408. if (url_fopen(&oc->pb, ofile, URL_WRONLY) < 0)
  409. {
  410. printf("Could not open file.\n");
  411. return -6;
  412. }
  413. }
  414. catch(...)
  415. {
  416. printf("Could not open file.\n");
  417. return -6;
  418. }
  419. }
  420. /* write the stream header, if any */
  421. if( 0 != av_write_header(oc))
  422. {
  423. printf("write the stream header failed.\n");
  424. return -7;
  425. }
  426. return 0;
  427. }

ffmpeg API录制rtsp视频流的更多相关文章

  1. 录制rtsp音视频

    1.使用ffmpeg来录制rtsp视频 视频 ffmpeg -y -i rtsp://172.16.23.66:554/h264major -vcodec copy -f mp4 record.mp4 ...

  2. 学习FFmpeg API

    ffmpeg是编解码的利器,用了很久,以前看过dranger 的教程,非常精彩,受益颇多,是学习ffmpeg api很好的材料.可惜的是其针对的ffmpeg版本已经比较老了,而ffmpeg的更新又很快 ...

  3. 【转】学习FFmpeg API – 解码视频

    ffmpeg是编解码的利器,用了很久,以前看过dranger 的教程,非常精彩,受益颇多,是学习ffmpeg api很好的材料.可惜的是其针对的ffmpeg版本已经比较老了,而ffmpeg的更新又很快 ...

  4. Ffmpeg 获取USB Camera 视频流

    本文讲述的案例是如何通过Ffmpeg实现从USB Camera中获取视频流并将视频流保存到MP4文件. 本文亦适用于从USB Camera 获取视频流并将视频流转发到rtmp服务的案例,二者基本的原理 ...

  5. OpenCV读取RTSP视频流

    用opencv的VideoCapture读取RTSP视频流,只有opencv3.1版本可以,之前的版本都无法读取视频流.可能的原因是云平台的RTSP视频流太差,经常错码.项目最后使用的是opencv2 ...

  6. Web下无插件播放rtsp视频流的方案及各家优秀内容资源整理

    Web下无插件播放rtsp视频流的方案及各家优秀内容资源整理 方案一:服务器端用 websocket 接受 rtsp ,然后,推送至客户端 实现步骤: 方案二:使用 ffmpeg + nginx 把 ...

  7. 谷歌浏览器Chrome播放rtsp视频流解决方案

    找半天,HTML5的可以支持RTMP 但是无法播放RTSP,flash也止步于RTMP,最后同事推荐了个开源的好东东 VLC ,请教谷歌大神之后,这货果然可以用来让各浏览器(IE activex方式, ...

  8. 如何用FFmpeg API采集摄像头视频和麦克风音频,并实现录制文件的功能

    之前一直用Directshow技术采集摄像头数据,但是觉得涉及的细节比较多,要开发者比较了解Directshow的框架知识,学习起来有一点点难度.最近发现很多人问怎么用FFmpeg采集摄像头图像,事实 ...

  9. 使用FFmpeg如何转发一个RTSP视频流

    版权声明:转载请说明出处:http://www.cnblogs.com/renhui/p/6930221.html   转发RTSP流,这类需求一般出现于转发一些摄像头采集视频,并在摄像头上做RTSP ...

随机推荐

  1. 给定N个整数集合是否存在两个其和刚好为指定常数的元素

    又一次学习一遍<算法导论>,看到了这个问题: 描写叙述一个执行时间为O(nlgn)的算法,使之能在给定一个由n个整数构成的集合S和还有一个整数 X 时,推断出S中是否存在有两个其和刚好等于 ...

  2. 达到XML简单的动态配置

    今天写的XML相关内容:随着上述眼前的小项目(等级类别)由于地图每个级别.因此,让他动态读取XML内容,这样的变化只能看到XML档. 简单的想法:第一次使用UserDefault类写入文件 UserD ...

  3. C++入门学习——标准模板库之vector

    vector(向量容器),是 C++ 中十分实用一个容器.vector 之所以被觉得是一个容器,是由于它可以像容器一样存放各种类型的对象,简单地说,vector 是一个可以存放随意类型(类型可以是in ...

  4. SQLLoader5(从多个数据文件导入到同一张表)

    从多个数据文件导入到同一张表很简单,只需要在INFILE参数指定多个数据文件的路径即可.数据文件1:test1.txt1111 ALLE SALESMAN2222 WARD SALESMAN数据文件2 ...

  5. SQL按汉语拼音首字母排序

    以常用到的省的数据表(province)为例,其中name字段为省的名称,SQL语句如下: ))) as py ,a.name from province a left outer join ( se ...

  6. Code Complete阅读笔记(二)

    2015-03-06   328   Unusual Data Types    ——You can carry this technique to extremes,putting all the ...

  7. C# 操作系统防火墙

    很多时候,我们的程序是通过网络通信(如TCP或者UDP协议+端口),而将制作好的程序安装包给客户用时,发现会出现不能通信的现象(或者在这台电脑是可以的,却在另一台不可以),原因是防火墙阻止了,需要添加 ...

  8. VS2012 运行项目在IE中可以运行,但是在google和firefox却不能打开。

    笔记本重装了系统之后,打开VS2012 调试的时候,发现在IE下能够运行调试.net项目,但是使用google和firefox的时候却不能打开项目.苦思冥想不知道是怎么回事儿,后来经过在网上查阅各种资 ...

  9. git rm

    git rm可以执行删除的条件(前提是要被删除的文件还没有从workspace tree中移除) git rm可以执行删除的条件:被删除文件在index当中的blob内容必须与HEAD commit指 ...

  10. XHTML 结构化:使用 XHTML 重构网站

    http://www.w3school.com.cn/xhtml/xhtml_structural_01.asp 我们曾经为本节撰写的标题是:"XHTML : 简单的规则,容易的方针.&qu ...