将原始 Genicam H.264 数据读取到 avlib

Read raw Genicam H.264 data to avlib

我尝试熟悉 libav,以便处理来自支持 GenICam 的摄像机的原始 H.264 流。 我想通过 GenICam 提供的接口 (API) 接收原始数据,然后将该数据转发到 libav 以生成一个容器文件,然后将其流式传输到播放设备,如 VLC 或(稍后)到自己实现的显示。

到目前为止,我使用了 GenICam 示例代码,它将原始 H.264 数据传输到 "sample.h264" 文件中。这个文件,我已经通过命令行工具 ffmpeg 放置,以生成一个我可以在 VLC 中打开和观看的 mp4 容器文件

command: ffmpeg -i "sample.h264" -c:v copy -f mp4 "out.mp4"

目前,我正在研究每个 H.264、ffmpeg、libav 和一般视频处理的示例和文档。我不得不承认,作为一个完全的初学者,它让我很困惑。 我正处于我认为我已经找到有助于我的事业的相应 libav 函数的地步:

我认为,基本上,我需要函数 avcodec_send_packet() 和 avcodec_receive_packet()(因为 avcodec_decode_video2() 已弃用)。 在此之前,我设置了一个 avCodedContext 结构并将其与 H.264 编解码器 (AV_CODEC_ID_H264).

打开(或合并?!?)

到目前为止,我的代码如下所示(省略了错误检查和其他内容):

...
AVCodecContext* avCodecContext = nullptr;
AVCodec *avCodec = nullptr;
AVPacket *avPacket = av_packet_alloc();
AVFrame *avFrame = nullptr;
...
avCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
avCodecContext = avcodec_alloc_context3(avCodec);
avcodec_open2 ( avCodecContext, avCodec, NULL );
av_init_packet(avPacket);
...

while(receivingRawDataFromCamera)
{
  ...
  // receive raw data via GenICam
  DSGetBufferInfo<void*>(hDS, sBuffer.BufferHandle, BUFFER_INFO_BASE, NULL, pPtr)

  // libav action
  avPacket->data =static_cast<uint8_t*>(pPtr);  
  avErr = avcodec_send_packet(avCodecContext, avPacket);
  avFrame = av_frame_alloc();
  avErr = avcodec_receive_frame( avCodecContext, avFrame);

  // pack frame in container? (not implemented yet)
  ..
}

上面代码的结果是,对 send_packet() 和 receive_frame() return 的调用都出现错误代码(-22 和 -11),我'我无法通过 av_strerror() 解密(它只说,这些是错误代码 22 和 11)。

编辑:对于那些想知道

avPacket->data = static_cast<uint8_t*>(pPtr);

是一个有效的操作... 第一次调用此操作后,avPacket->data 的内容为

{0x0, 0x0, 0x0, 0x1, 0x67, 0x64, 0x0, 0x28, 0xad, 0x84, 0x5,
  0x45, 0x62, 0xb8, 0xac, 0x54, 0x74, 0x20, 0x2a, 0x2b, 0x15, 0xc5,
  0x62}

由于开头的 NAL 标记和数字,这在某种程度上看起来是意料之中的事情? 我不知道,因为我真的是一个初学者....

现在的问题是,我走的路对吗?缺少什么以及代码 22 和 11 是什么意思?

下一个问题是,之后要做什么才能获得可以(实时)流式传输给玩家的容器?

提前致谢, 迈克

至少对于最初提出的问题,我找到了适合自己的解决方案:

为了消除调用函数时的错误

avcodec_send_packet(avCodecContext, avPacket);
...
avcodec_receive_frame( avCodecContext, avFrame);

我不得不手动填写 'avCodecContext' 和 'avPacket' 的一些参数:

avCodecContext->bit_rate = 8000000;
avCodecContext->width = 1920;
avCodecContext->height = 1080;
avCodecContext->time_base.num = 1;
avCodecContext->time_base.den = 25;
...
avPacket->data = static_cast<uint8_t*>(pPtr);
avPacket->size = datasize;
avPacket->pts = frameid;

而 'datasize' 和 'frameid' 是通过 GenICam 接收的,可能不是字段的适当参数,但至少我不会再收到任何错误了。

既然这回答了我最初关于如何将原始数据放入 libav 结构的问题,我认为问题就得到了回答。

评论区的讨论和建议with/from Vencat 引出了我的其他问题,但我想应该在一个新问题中讨论这些问题。