当前位置:文档之家› ffmpeg 最简单的转码封装mp4文件

ffmpeg 最简单的转码封装mp4文件

ffmpeg 最简单的转码封装mp4文件
ffmpeg 最简单的转码封装mp4文件

ffmpeg 最简单的转码封装mp4文件

分类:C/C++

本例简单实现了解码后的video重新编码264之后在mux成MP4文件的过程,主要是用来记录muxing的方法。

下面详细说一下细节:

大家都知道一般解码出来的数据都是播放顺序,解码器是将编码顺序的数据重新按照解码后的播放顺序输出的。而编码器是把数据根据解码需要的顺序重新排序保存的。

当然,以上情况只在有帧的情况下才有用,否则只有IP帧的话解码和编码的顺序是一样的

比如:解码后的数据是IBBP,那要将这个数据编码的话,编码后的数据保存的格式就是IPBB

这只是内部的处理,对于用ffmpeg的库的我们不用太过关心,但是,要注意,我们将数据塞给编码器的时候,要给顺序的播放加上顺序的时间标记,其实很简单只要保证你送给编码器的每一frame的pts都是顺序的就可以了,否则编码器会报“non-strictly-monotonic pts at frame” ,究其原因,是因为编码器需要送进来的frame时间上是递增的,为什么需要这个就得去本研究编码器了

点击(此处)折叠或打开

1.if( pic.i_pts <= largest_pts )

2.{

3.if( cli_log_level >= X264_LOG_DEBUG || pts_warning_cnt < MAX_P

TS_WARNING )

4. x264_cli_log("x264", X264_LOG_WARNING,"non-strictly-mono

tonic pts at frame %d (%"PRId64" <= %"PRId64")\n",

5. i_frame, pic.i_pts, largest_pts );

6.else if( pts_warning_cnt == MAX_PTS_WARNING )

7. x264_cli_log("x264", X264_LOG_WARNING,"too many nonmonot

onic pts warnings, suppressing further ones\n");

8. pts_warning_cnt++;

9. pic.i_pts = largest_pts + ticks_per_frame;

10.}

在将数据送到编码器后,进行编码输出得到的pkt有自己的pts和dts等数据,但是这个数据记得吗?是用我们自己送进去的pts来表示的,所以在和原来的audio mux的时候,会出现严重的音视频不同步,现在想想这个问题,就很容易理解了,两边的pts差距很大,当然解码后做同步的时候会差很多。

其实ffmpeg在解码的时候将解码出来的顺序时间戳给了frame的pkt_pts这个成员,所以我们可以直接用这个值赋值给frame的pts,在送进编码器,这样编码出来的pkt中的时间戳就和原来的audio对上了。

点击(此处)折叠或打开

1.ret = avcodec_decode_video2(video_dec_ctx, pFrame,&got_picture, pkt);

2.if(ret < 0)

3.{

4. delete pkt;

5. return 0;

6.}

7. pFrame->pts = pFrame->pkt_pts; //赋值解码后的pts

最后在进行mux成mp4文件就ok了

在mux的过程中,有个接口av_rescale_q_rnd,这个是用来换算pts的,因为在设定mp4输出格式的时候time_base这个值是和原来的文件不一样的,所以要用这个来重新算分装数据的在新的mp4中的pts和dts等数据,具体原因后续会继续往里研究

直接上代码:

点击(此处)折叠或打开

1.const char* SRC_FILE ="1.mkv";

2.const char* OUT_FILE ="outfile.h264";

3.const char* OUT_FMT_FILE ="outfmtfile.mp4";

4.int main()

5.{

6. av_register_all();

7.

8.

9.

10. AVFormatContext* pFormat =NULL;

11.if(avformat_open_input(&pFormat, SRC_FILE,NULL,NULL)< 0)

12.{

13. return 0;

14.}

15. AVCodecContext* video_dec_ctx =NULL;

16. AVCodec* video_dec =NULL;

17.if(avformat_find_stream_info(pFormat,NULL)< 0)

18.{

19. return 0;

20.}

21. av_dump_format(pFormat, 0, SRC_FILE, 0);

22. video_dec_ctx = pFormat->streams[0]->codec;

23. video_dec = avcodec_find_decoder(video_dec_ctx->codec_id);

24.if(avcodec_open2(video_dec_ctx, video_dec,NULL)< 0)

25.{

26. return 0;

27.}

28.

29. AVFormatContext* pOFormat =NULL;

30. AVOutputFormat* ofmt =NULL;

31.if(avformat_alloc_output_context2(&pOFormat,NULL,NULL, OUT_FILE)<

0)

32.{

33. return 0;

34.}

35. ofmt = pOFormat->oformat;

36.if(avio_open(&(pOFormat->pb), OUT_FILE, AVIO_FLAG_READ_WRITE)< 0)

37.{

38. return 0;

39.}

40. AVCodecContext *video_enc_ctx =NULL;

41. AVCodec *video_enc =NULL;

42. video_enc = avcodec_find_encoder(AV_CODEC_ID_H264);

43. AVStream *video_st = avformat_new_stream(pOFormat, video_enc);

44.if(!video_st)

45. return 0;

46. video_enc_ctx = video_st->codec;

47. video_enc_ctx->width = video_dec_ctx->width;

48. video_enc_ctx->height = video_dec_ctx->height;

49. video_enc_ctx->pix_fmt = PIX_FMT_YUV420P;

50. video_enc_ctx->time_base.num = 1;

51. video_enc_ctx->time_base.den = 25;

52. video_enc_ctx->bit_rate = video_dec_ctx->bit_rate;

53. video_enc_ctx->gop_size = 250;

54. video_enc_ctx->max_b_frames = 10;

55.//H264

56.//pCodecCtx->me_range = 16;

57.//pCodecCtx->max_qdiff = 4;

58. video_enc_ctx->qmin = 10;

59. video_enc_ctx->qmax = 51;

60.if(avcodec_open2(video_enc_ctx, video_enc,NULL)< 0)

61.{

62. printf("编码器打开失败!\n");

63. return 0;

64.}

65. printf("Output264video Information====================\n");

66. av_dump_format(pOFormat, 0, OUT_FILE, 1);

67. printf("Output264video Information====================\n");

68.

69.//mp4 file

70. AVFormatContext* pMp4Format =NULL;

71. AVOutputFormat* pMp4OFormat =NULL;

72.if(avformat_alloc_output_context2(&pMp4Format,NULL,NULL, OUT_FMT_FI

LE)< 0)

73.{

74. return 0;

75.}

76. pMp4OFormat = pMp4Format->oformat;

77.if(avio_open(&(pMp4Format->pb), OUT_FMT_FILE, AVIO_FLAG_READ_WRITE)<

0)

78.{

79. return 0;

80.}

81.

82.for(int i = 0; i < pFormat->nb_streams; i++){

83. AVStream *in_stream = pFormat->streams[i];

84. AVStream *out_stream = avformat_new_stream(pMp4Format, in_stream->

codec->codec);

85.if(!out_stream){

86. return 0;

87.}

88.int ret = 0;

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

90.if(ret < 0){

91. fprintf(stderr,"Failed to copy context from input to output s

tream codec context\n");

92. return 0;

93.}

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

95.if(pMp4Format->oformat->flags & AVFMT_GLOBALHEADER)

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

97.}

98.

99.

100. av_dump_format(pMp4Format, 0, OUT_FMT_FILE, 1);

101.

102.if(avformat_write_header(pMp4Format,NULL)< 0)

103.{

104. return 0;

105.}

106.

107.

108.////

109.

110.

111.

112. av_opt_set(video_enc_ctx->priv_data,"preset","superfast", 0);

113. av_opt_set(video_enc_ctx->priv_data,"tune","zerolatency", 0);

114. avformat_write_header(pOFormat,NULL);

115. AVPacket *pkt = new AVPacket();

116. av_init_packet(pkt);

117. AVFrame *pFrame = avcodec_alloc_frame();

118.int ts = 0;

119.while(1)

120.{

121.if(av_read_frame(pFormat, pkt)< 0)

122.{

123. avio_close(pOFormat->pb);

124. av_write_trailer(pMp4Format);

125. avio_close(pMp4Format->pb);

126. delete pkt;

127. return 0;

128.}

129.if(pkt->stream_index == 0)

130.{

131.

132.int got_picture = 0, ret = 0;

133. ret = avcodec_decode_video2(video_dec_ctx, pFrame,&got_pictur e, pkt);

134.if(ret < 0)

135.{

136. delete pkt;

137. return 0;

138.}

139. pFrame->pts = pFrame->pkt_pts;//ts++;

140.if(got_picture)

141.{

142. AVPacket *tmppkt = new AVPacket;

143. av_init_packet(tmppkt);

144.int size = video_enc_ctx->width*video_enc_ctx->height * 3 / 2;

145. char* buf = new char[size];

146. memset(buf, 0, size);

147. tmppkt->data =(uint8_t*)buf;

148. tmppkt->size = size;

149. ret = avcodec_encode_video2(video_enc_ctx, tmppkt, pFrame, &got_picture);

150.if(ret < 0)

151.{

152. avio_close(pOFormat->pb);

153. delete buf;

154. return 0;

155.}

156.if(got_picture)

157.{

158.//ret = av_interleaved_write_frame(pOFormat, tmppkt); 159. AVStream *in_stream = pFormat->streams[pkt->stream_ind ex];

160. AVStream *out_stream = pMp4Format->streams[pkt->stream _index];

161.

162. tmppkt->pts = av_rescale_q_rnd(tmppkt->pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);

163. tmppkt->dts = av_rescale_q_rnd(tmppkt->dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);

164. tmppkt->duration = av_rescale_q(tmppkt->duration, in_s tream->time_base, out_stream->time_base);

165. tmppkt->pos =-1;

166. ret = av_interleaved_write_frame(pMp4Format, tmppkt); 167.if(ret < 0)

168. return 0;

169. delete tmppkt;

170. delete buf;

171.}

172.}

173.//avcodec_free_frame(&pFrame);

174.}

175.else if(pkt->stream_index == 1)

176.{

177. AVStream *in_stream = pFormat->streams[pkt->stream_index]; 178. AVStream *out_stream = pMp4Format->streams[pkt->stream_index]; 179.

180. pkt->pts = av_rescale_q_rnd(pkt->pts, in_stream->time_base, ou t_stream->time_base, AV_ROUND_NEAR_INF);

181. pkt->dts = av_rescale_q_rnd(pkt->dts, in_stream->time_base, ou t_stream->time_base, AV_ROUND_NEAR_INF);

182. pkt->duration = av_rescale_q(pkt->duration, in_stream->time_ba se, out_stream->time_base);

183. pkt->pos =-1;

184.if(av_interleaved_write_frame(pMp4Format, pkt)< 0)

185. return 0;

186.}

187.}

188. avcodec_free_frame(&pFrame);

189. return 0;

190.}

阅读(4898) | 评论(0) | 转发(0) |

上一篇:ffmpeg 最简单的编码264

下一篇:设计模式-工厂模式与抽象工厂模式

相关主题
文本预览
相关文档 最新文档