使用FFMPEG从H264制作HLS剪辑

时间:2017-11-20 14:45:57

标签: ffmpeg h.264 hls

我正在使用HiSilicon的Hi35xx相机处理器。这是一架Arm9,侧面用螺栓固定视频管道。在管道的一端是CMOS传感器。另一端是H264编码器。当我打开管道时,编码器输出H264 NAL数据包,如下所示:

frame0: <SPS>,<PPS>,<SEI>,<key frame>
frame1: <delta frame>
frame2: <delta frame>
...
frameN: <delta frame>
frameN+1: <SPS>,<PPS>,<SEI><key frame>
frameN+2: <delta frame>
frameN+3: <delta frame>
...
etc.

我通过执行以下操作将其转换为HLS剪辑(为了清晰起见,伪代码):

av_register_all();
avformat_network_init();

avformat_alloc_output_context2(&ctx_out, NULL, "hls", "./foo.m3u8");

strm_out = avformat_new_stream(ctx_out, NULL);

codec_out = strm_out->codecpar;
codec_out->codec_id = AV_CODEC_ID_H264;
codec_out->codec_type = AVMEDIA_TYPE_VIDEO;
codec_out->width = encoder_width;
codec_out->height = encoder_height;
codec_out->bit_rate = encoder_bitrate;
codec_out->codec_tag = 0;

avformat_write_header(ctx_out, NULL);

while(get_packet_from_pipeline_encoder(&encoder_packet)) {
  AVPacket pkt;
  av_init_packet(&pkt);
  pkt.stream_index = 0;

  pkt.dts = AV_NOPTS_VALUE;
  pkt.pts = AV_NOPTS_VALUE;
  pkt.duration = (1000000/FRAMERATE);    // frame rate in microseconds

  pkt.data = encoder_packet.data;
  pkt.size = encoder_packet.size;

  if (is_keyframe(&encoder_packet)) {
    pkt.flags |= AV_PKT_FLAG_KEY;
  }

  av_write_frame(ctx_out, &pkt);
}

av_write_trailer(ctx_out);
avformat_free_context(ctx_out);

除了生成的HLS帧速率不正确之外,这似乎工作正常。当然,这是因为我没有正确设置pts / dts的东西而且ffmpeg让我知道。所以我有两个问题:

  1. 我这样做了吗?
  2. 如何正确设置pts / dts内容?
  3. 编码器正在给我数据包,我将它们作为帧提交。那些<SPS>, <PPS> and <SEI>数据包实际上是带外数据,并没有真正的时间戳。我该如何正确提交?

1 个答案:

答案 0 :(得分:0)

我的结论是我错误地走了这条路。基本问题是我没有输入上下文,所以没有h264解析器可以接收SPS,PPS和SEI数据包并对它们做任何事情。我怀疑我的循环似乎正在起作用,因为我正在写一个&#39; mpegts&#39;文件只是带有前导NAL零的h264数据包替换为长度字(某些比特流过滤器正在这样做)。但这意味着我没有机会获得正确的时间戳,因为我必须将它们作为帧提交。我无法将其作为“extradata / sidedata”提交。因为没有解码器来捕捉它们。

通过为编码器的输出编写自定义IO上下文然后执行正常的输入上下文来解决此问题。我用这种方法做了一些实验,似乎有效。