开发环境:
WINDOWS7 32bit
MINGW
eclipse juno cdt
1、首先你要编译好FFMPEG,
a) 方法一:可以去官网下载源码,用MINGW编译(编译时记得支持H264,当然,事先得下载并编译好libx264,视频技术论坛里有很多介绍)
b) 方法二:更加省心省力的方法是,下载别人已经编译好的资源,如ZeranoeFFmpeg的,下载他的dev版本,包含了头文件,链接库等必须的东西,当然,这东西已经是支持H264的了。
2、以下的就是代码部分了:
a) 先声明必要的变量:

  1. AVFormatContext *fmtctx;
  2. AVStream *video_st;
  3. AVCodec *video_codec;
  4. const int FPS = 25; /* 25 images/s */
  5. const char *RDIP = “127.0.0.1”;
  6. unsigned int  RDPORT = 5678;
  7. const unsigned int OUTWIDTH = 720;
  8. const unsigned int OUTHEIGHT = 480;
  9. av_register_all();
  10. avformat_network_init();

复制代码

b) 初始化AV容器

  1. fmtctx = avformat_alloc_context();

复制代码

c) 获得输出格式,这里是RTP网络流

  1. fmtctx->oformat = av_guess_format("rtp", NULL, NULL);

复制代码

d)打开网络流

  1. snprintf(fmtctx->filename, sizeof(fmtctx->filename),"rtp://%s:%d",RDIP,RDPORT);
  2. avio_open(&fmtctx->pb,fmtctx->filename, AVIO_FLAG_WRITE)

复制代码

e) 开始添加H264视频流

  1. video_st = NULL;video_st = add_video_stream(fmtctx, &video_codec, AV_CODEC_ID_H264);

复制代码

其中,add_video_stream函数为:

  1. add_video_stream(AVFormatContext *oc,AVCodec **codec, enum AVCodecID codec_id)
  2. {
  3. AVCodecContext *c;
  4. AVStream *st;
  5. /* find the video encoder */
  6. *codec = avcodec_find_encoder(codec_id);
  7. st = avformat_new_stream(oc, *codec);
  8. c = st->codec;
  9. avcodec_get_context_defaults3(c, *codec);
  10. c->codec_id = codec_id;
  11. c->width = OUTWIDTH;
  12. c->height = OUTHEIGHT;
  13. c->time_base.den = FPS;
  14. c->time_base.num = 1;
  15. c->pix_fmt = PIX_FMT_YUV420P;
  16. if(oc->oformat->flags & AVFMT_GLOBALHEADER)
  17. c->flags|= CODEC_FLAG_GLOBAL_HEADER;
  18. av_opt_set(c->priv_data, "preset", "ultrafast", 0);
  19. av_opt_set(c->priv_data, "tune","stillimage,fastdecode,zerolatency",0);
  20. av_opt_set(c->priv_data, "x264opts","crf=26:vbv-maxrate=728:vbv-bufsize=364:keyint=25",0);return st;}
  21. // OPEN THE CODE
  22. avcodec_open2(video_st->codec, video_codec, NULL);
  23. /* Write the stream header, if any. */
  24. avformat_write_header(fmtctx, NULL);

复制代码

f) 现在,就可以不断的编码数据,并发生数据了

  1. AVFrame* m_pYUVFrame = avcodec_alloc_frame();
  2. while(1) //这里设置成无限循环,你可以设置成250,或其他数进行测试,观看结果
  3. {
  4. fill_yuv_image(m_pYUVFrame, video_st->codec->frame_number,OUTWIDTH, OUTHEIGHT);
  5. /* encode the image */
  6. AVPacket pkt;
  7. int got_output = 0;
  8. av_init_packet(&pkt);
  9. pkt.data = NULL;    // packet data will be allocated by the encoder
  10. pkt.size = 0;
  11. pkt.pts = AV_NOPTS_VALUE;
  12. pkt.dts =AV_NOPTS_VALUE;
  13. m_pYUVFrame->pts = video_st->codec->frame_number;
  14. ret = avcodec_encode_video2(c, &pkt,frame, &got_output);
  15. if (ret < 0) {fprintf(stderr, "Error encoding video frame: %s\n", av_err2str(ret));
  16. exit(1);
  17. }
  18. /* If size is zero, it means the image was buffered. */
  19. if (got_output)
  20. {
  21. if (c->coded_frame->key_frame)pkt.flags |= AV_PKT_FLAG_KEY;
  22. pkt.stream_index = st->index;
  23. if (pkt.pts != AV_NOPTS_VALUE )
  24. {
  25. pkt.pts = av_rescale_q(pkt.pts,video_st->codec->time_base, video_st->time_base);
  26. }
  27. if(pkt.dts !=AV_NOPTS_VALUE )
  28. {
  29. pkt.dts = av_rescale_q(pkt.dts,video_st->codec->time_base, video_st->time_base);
  30. }
  31. /* Write the compressed frame to the media file. */
  32. ret = av_interleaved_write_frame(oc,&pkt);
  33. }
  34. else {
  35. ret = 0;
  36. }
  37. }

复制代码

g) Fill_yuv_image函数:

  1. /* Prepare a dummy image. */
  2. static void fill_yuv_image(AVPicture *pict,int frame_index,int width, int height)
  3. {
  4. int x, y, i;
  5. i = frame_index;
  6. /* Y */
  7. for (y = 0; y < height; y++)
  8. for (x = 0; x < width; x++)
  9. pict->data[0][y * pict->linesize[0] +x] = x + y + i * 3;
  10. /* Cb and Cr */
  11. for (y = 0; y < height / 2; y++)
  12. {
  13. for (x = 0; x < width / 2; x++)
  14. {
  15. pict->data[1][y * pict->linesize[1] +x] = 128 + y + i * 2;
  16. pict->data[2][y * pict->linesize[2] +x] = 64 + x + i * 5;
  17. }
  18. }
  19. }

复制代码

h) 打印sdp信息,仅需一次,打印的sdp信息,用在VLC播放器结束网络视频流时用到

  1. //打印sdp信息
  2. char sdp[2048];
  3. av_sdp_create(&fmtctx,1, sdp, sizeof(sdp));
  4. printf("%s\n",sdp);
  5. fflush(stdout);

复制代码

i)最后,做一些清理工作

  1. avcodec_free_frame(&m_pYUVFrame);
  2. av_write_trailer(fmtctx);
  3. /* Free the streams. */
  4. for (unsigned int i = 0; i< fmtctx->nb_streams;i++)
  5. {
  6. av_freep(&fmtctx->streams->codec);
  7. av_freep(&fmtctx->streams);
  8. }
  9. if(!(fmtctx->oformat->flags& AVFMT_NOFILE))
  10. /* Close the output file. */
  11. avio_close(fmtctx->pb);
  12. /*free the stream */
  13. av_free(fmtctx);

复制代码

3、编译代码,记得添加库文件,运行一次代码,不用死循环,设置不用循环,因为是要让他打印出sdp文件的信息。得到sdp信息,比如我精简成如下:

  1. c=IN IP4 127.0.0.1
  2. m=video 56782 RTP/AVP 96
  3. a=rtpmap:96 H264/90000
  4. a=framerate:25
  5. a=fmtp:96 packetization-mode=1

复制代码

把这些信息保存到一个文本文件,并改名为sdp后缀,如mySDP.sdp。
4、从官网下载VLC播放器,重新运行上述的代码,这一次要循环,具体循环多久,你自己决定,这一次是正式测试了。代码跑起来后,把刚刚的sdp文件用VLC打开,直接把sdp文件拖到VLC播放器中就行了。等待缓冲,就可以看到效果了。
5、代码中剩掉了出错检查部分,请自行添加。
6、关于IP地址,这里是127.0.0.1,是供本机测试,可以改成制定的接受数据的电脑IP地址,或者广播地址IP地址。
7、经本人测试,局域网内不同电脑间测试,刚开始播放良好,进过一段时间后,开始出现吊针现象。经多次修改av_opt_set里面的参数(是修改x264的参数配置)也无法达到较理想的想过。

【FFMPEG】使用FFMPEG+H264实现RTP传输数据的更多相关文章

  1. ffmpeg摄像头采集h264编码RTP发送

    一. 相关API说明 1. av_register_all 2. avformat_network_init 不管是流媒体发送还是流媒体接收, 需要先执行该函数. 3. avformat_alloc_ ...

  2. Linux下源码安装ffmpeg及ffmpeg的简单使用说明

    一.编译安装 ffmpeg在安装时依赖的包和版本都很让人头疼,不同编译环境也各不相同.公司之前封装了一个又各种出错. 其实办法很简单,就是到官网一步一步按着做就行了:http://trac.ffmpe ...

  3. RTP/RTCP(一)-H264关于RTP协议的实现

    H264关于RTP协议的实现2010-07-22 13:35完整的C/S架构的基于RTP/RTCP的H.264视频传输方案.此方案中,在服务器端和客户端分别进行了功能模块设计.服务器端:RTP封装模块 ...

  4. (转载)[FFmpeg]使用ffmpeg从各种视频文件中直接截取视频图片

    你曾想过从一个视频文件中提取图片吗?在Linux下就可以,在这个教程中我将使用ffmpeg来从视频中获取图片. 什么是ffmpeg?What is ffmpeg? ffmpeg是一个非常有用的命令行程 ...

  5. H264的RTP负载打包的数据包格式,分组,分片

    H264的RTP负载打包的数据包格式,分组,分片 1.    RTP数据包格式 RTP报文头格式(见RFC3550 Page12): 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 ...

  6. ffmpeg yuv转h264

    ffmpeg -s 176x144 -i  container_qcif_176_144.yuv -b:v 7776k -r 25 -vcodec libx264 ds.h264

  7. 使用ffmpeg实现对h264视频解码 -- (实现了一个易于使用的c++封装库)

    H264是当今流行的视频压缩格式:ffmpeg是一个开源库,实现了对h264视频文件的解压缩. 为了降低使用ffmpeg的复杂性,尽量隐藏实现细节,我写了一个封装库.c#也可以很方便的使用此库.解压后 ...

  8. (转)MP4文件两种格式AVC1和H264的区别及利用FFMPEG demux为h264码流事项

    出自:http://www.mworkbox.com/wp/work/314.html 2013-05-04 MP4的视频H264封装有2种格式:h264和avc1,对于这个细节,很容易被忽略.笔者也 ...

  9. ffmpeg只编译h264

    ./configure --arch=arm --cross-prefix=arm-none-linux-gnueabi- --extra-ldflags=-static --target-os=li ...

随机推荐

  1. [React] Reduce Code Redundancy with Custom React Hooks

    In this lesson, we'll cover how to create a custom React hook for managing the state of any input. T ...

  2. 题解 [BZOJ1295][SCOI2009] 最长距离

    题面 解析 \(n\)只有\(30\)可以直接枚举每个矩形, 判断他们的左上角到右下角或右上角到左上角的最短路是否小于\(T\). 最短路可以用\(dijkstra\). 一开始想用\(DP\)写最短 ...

  3. Educational Codeforces Round 33 (Rated for Div. 2) C题·(并查集变式)

    C. Rumor Vova promised himself that he would never play computer games... But recently Firestorm — a ...

  4. Luogu P2511 [HAOI2008]木棍分割 二分+DP

    思路:二分+DP 提交:3次 错因:二分写萎了,$cnt$记录段数但没有初始化成$1$,$m$切的次数没有$+1$ 思路: 先二分答案,不提: 然后有个很$naive$的$DP$: 设$f[i][j] ...

  5. code命令用vscode打开项目代码

    1. 打开vscode, 使用Command + shift + p, 输入shelll 选择

  6. 在chrome开发者模式中查找你的js文件

    在chrom开发者模式中按ctrl+o查找你的js文件

  7. javascript面向对象 用new创建一个基于原型的javascript对象

    //创建一个类 其实就是个对象 var Student={ name:"robot", height:1.6, run:function(){ console.log(this.n ...

  8. NSNull

    集合中是不能放nil值的,因为nil是结尾,但是为了存放表示什么都没有的值,可以使用NSNull,它也是NSObject的一个子类. void null(){ NSNull *nl=[NSNull n ...

  9. AtCoder AGC001E BBQ Hard (DP、组合计数)

    题目链接: https://atcoder.jp/contests/agc001/tasks/agc001_e 题解: 求\(\sum^n_{i=1}\sum^n_{j=i+1} {A_i+A_j+B ...

  10. Java中局部变量、实例变量和静态变量在方法区、栈内存、堆内存中的分配

    转自:https://blog.csdn.net/leunging/article/details/80599282 感谢CSDN博主「leunging」的总结分享 ———————————————— ...