为什么说是裸流呢,因为这篇只讲到把视频编码后写入文件,得到的是一个后缀应该为“.h264”的文件,只能用PotPlayer等功能强大的播放器才能打开,因为它没有容器信息,需要装在MP4、MKV之类的容器中,才是一个真正的视频文件。但这一篇只讲编码后直接写入文件,以生成一个H264裸流文件。

代码是从FFMPEG的2.8版本的官方示例中搬运的:https://ffmpeg.org/doxygen/2.8/decoding_encoding_8c-example.html

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

static void video_encode_example(const char *filename, int codec_id)

{

AVCodec *codec;

AVCodecContext *c= NULL;

int i, ret, x, y, got_output;

FILE *f;

AVFrame *frame;

AVPacket pkt;

uint8_t endcode[] = { 0, 0, 1, 0xb7 };

printf("Encode video file %s\n", filename);

/* find the mpeg1 video encoder */

codec = avcodec_find_encoder(codec_id);

if (!codec) {

fprintf(stderr, "Codec not found\n");

exit(1);

}

c = avcodec_alloc_context3(codec);

if (!c) {

fprintf(stderr, "Could not allocate video codec context\n");

exit(1);

}

/* put sample parameters */

c->bit_rate = 400000;

/* resolution must be a multiple of two */

c->width = 352;

c->height = 288;

/* frames per second */

c->time_base = (AVRational){1,25};

/* emit one intra frame every ten frames

* check frame pict_type before passing frame

* to encoder, if frame->pict_type is AV_PICTURE_TYPE_I

* then gop_size is ignored and the output of encoder

* will always be I frame irrespective to gop_size

*/

c->gop_size = 10;

c->max_b_frames = 1;

c->pix_fmt = AV_PIX_FMT_YUV420P;

if (codec_id == AV_CODEC_ID_H264)

av_opt_set(c->priv_data, "preset", "slow", 0);

/* open it */

if (avcodec_open2(c, codec, NULL) < 0) {

fprintf(stderr, "Could not open codec\n");

exit(1);

}

f = fopen(filename, "wb");

if (!f) {

fprintf(stderr, "Could not open %s\n", filename);

exit(1);

}

frame = av_frame_alloc();

if (!frame) {

fprintf(stderr, "Could not allocate video frame\n");

exit(1);

}

frame->format = c->pix_fmt;

frame->width  = c->width;

frame->height = c->height;

/* the image can be allocated by any means and av_image_alloc() is

* just the most convenient way if av_malloc() is to be used */

ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height,

c->pix_fmt, 32);

if (ret < 0) {

fprintf(stderr, "Could not allocate raw picture buffer\n");

exit(1);

}

/* encode 1 second of video */

for (i = 0; i < 25; i++) {

av_init_packet(&pkt);

pkt.data = NULL;    // packet data will be allocated by the encoder

pkt.size = 0;

fflush(stdout);

/* prepare a dummy image */

/* Y */

for (y = 0; y < c->height; y++) {

for (x = 0; x < c->width; x++) {

frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;

}

}

/* Cb and Cr */

for (y = 0; y < c->height/2; y++) {

for (x = 0; x < c->width/2; x++) {

frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;

frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;

}

}

frame->pts = i;

/* encode the image */

ret = avcodec_encode_video2(c, &pkt, frame, &got_output);

if (ret < 0) {

fprintf(stderr, "Error encoding frame\n");

exit(1);

}

if (got_output) {

printf("Write frame %3d (size=%5d)\n", i, pkt.size);

fwrite(pkt.data, 1, pkt.size, f);

av_free_packet(&pkt);

}

}

/* get the delayed frames */

for (got_output = 1; got_output; i++) {

fflush(stdout);

ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);

if (ret < 0) {

fprintf(stderr, "Error encoding frame\n");

exit(1);

}

if (got_output) {

printf("Write frame %3d (size=%5d)\n", i, pkt.size);

fwrite(pkt.data, 1, pkt.size, f);

av_free_packet(&pkt);

}

}

/* add sequence end code to have a real mpeg file */

fwrite(endcode, 1, sizeof(endcode), f);

fclose(f);

avcodec_close(c);

av_free(c);

av_freep(&frame->data[0]);

av_frame_free(&frame);

printf("\n");

}

将上述代码中的AVFrame改为从摄像头获取的AVFrame,就实现了摄像头数据编码为H264裸流了,但有几点要注意。

  1. 代码中的av_opt_set(c->priv_data, "preset", "slow", 0)声明了编码速度,值有ultrafast、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、placebo,越快视频质量则越差,但如果想实现实时编码(即编码速度不慢于输入速度),还要加一句av_opt_set(pOutputVideoCodecCtx->priv_data, "tune", "zerolatency", 0)。
  2. 每个packet的pts非常重要,当然也比较简单,设置好帧率(time_base)之后,pts累加即可。
  3. 最后的“get the delayed frames”也叫作“flush encoder”,意思是编码器中一般会缓存一些数据,最后要取出来。第1点中提到的编码速度越快,编码器中缓存的Packet也会越少,反之则越多。

编码为H264裸流并写文件一相关推荐

  1. ffmpeg封装h264裸流为mp4文件,视频播放速度特别慢-解决

    计算实际帧率时,需要从mp4的moov box中的mvhd中取得timescale和duration,将两者相除得到文件总时长, 再从stsz box中取得sample总数,即总帧数sample_co ...

  2. ffmpeg封装h264裸流为mp4文件,视频播放速度特别慢

    计算实际帧率时,需要从mp4的moov box中的mvhd中取得timescale和duration,将两者相除得到文件总时长, 再从stsz box中取得sample总数,即总帧数sample_co ...

  3. FFmpeg解码H264裸流并转换成opencv Mat

    感谢雷霄骅博士的在中文视频编解码的付出,http://blog.csdn.net/leixiaohua1020 最近要搞一些视频推流的事情,要解析H264裸流并且获取opencv格式的Mat数据给算法 ...

  4. ffmpeg实现将H264裸流封装成.mp4或.avi文件

    ffmpeg学习历程 由于我是移植到arm-linux环境(海思HI3521A),H264裸流直接从海思的编码模块VENC获取. H264数据流序列:    SPS, PPS, SEI, I, P, ...

  5. RTSP再学习 -- 利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/78214267 既然已经可以通过 RTSP 获取h264 裸流了.那么通过 F ...

  6. 音视频开发(17)---RTSP再学习 -- 利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中

    RTSP再学习 -- 利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中 https://blog.csdn.net/qq_29350001/article/details/7821426 ...

  7. h264 裸流打包成mp4 注意事项

    需求: Android 端把网络摄像头的一段正在播放的视频流,截取保存成mp4(按录像按钮时开始录像). 实现: ffmpeg + x264 + sdl; h264 裸流 打包成MP4,在网上也有一大 ...

  8. 【嵌入式开发】用 VLC 显示 树莓派摄像头 H264 裸流

    首先树莓派连上网络,并和电脑在同一网段. 树莓派的IP是: 192.168.3.13 电脑的IP是: 192.168.3.6 1.在树莓派上采集 H264裸流,并用UDP发送到电脑. pi@Neil- ...

  9. java rtp 分片_RTP 协议解包为 H264 裸流

    RTP 协议解包为 H264裸流 一. 为什么使用 RTP 协议? TCP 传输流媒体数据由于其可靠性,会造成很大的网络延时和卡顿. UDP 传输由于其不可靠性,会导致丢帧,如果是关键帧,则会花屏一个 ...

最新文章

  1. Macbook air 键盘标点符号怎么输出?
  2. att格式汇编指令_ARM汇编伪指令介绍.
  3. VS调试时怎么跳过for循环?
  4. Jmeter将JDBC Request查询结果作为下一个接口参数方法
  5. [水煮 ASP.NET Web API2 方法论](1-6)Model Validation
  6. python3.6.5安装tensorflow_Win10下用Anaconda安装TensorFlow(图文教程)
  7. 【CVPR2019】Workshops 研讨会列表及链接
  8. pom.xml 如果使用 mvn exec:exec 命令运行项目
  9. 平安夜福利,送3本《从0到1搭建自动化测试框架》
  10. MapServer使用笔记(二)
  11. eXeScope的应用
  12. 深度学习模型---稀疏编码 Sparse Coding
  13. exosip 对比osip
  14. Python计算某年某月某日天数
  15. Go 语言开发工具 LiteIDE x22 发布
  16. c语言找最大数字,C语言: 键盘输入任意10个整数,找出最大数及最大数的序号。...
  17. 查询oracle数据库表名和中文名
  18. CSDN博客运营团队2022年H2总结
  19. 阿朵洒洒的撒多撒多撒啊
  20. 2021四川高考成绩等位分查询,2021年四川高考位次排名查询,四川高考位次所对应的学校...

热门文章

  1. 微信公众号 php支付代码,微信支付PHPSDK之微信公众号支付代码详解
  2. oracle分类函数总结,oracle中分组排序函数用法
  3. 网付资讯:刷脸支付代理是正规的吗?
  4. 2021年暑假数学建模第一次模拟赛:新冠疫情预测(插值,时间序列,微分方程建模)
  5. Undefined symbol longjmp
  6. Mac,Linux中用mkdir同时创建多个文件夹
  7. 谈谈端到端测试(End-to-End Testing)
  8. RTT-KEIL-AC6编译问题
  9. Excel 多个单元格合并到一个单元格中的函数
  10. 开源的python有限元软件_Python与有限元--基于Python编程的有限元分析及应用扩展...