0

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

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

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() 的调用都返回错误代码(-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 是什么意思?

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

在此先感谢,迈克

4

1 回答 1

0

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

为了摆脱调用函数的错误

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 结构的问题,我认为,这个问题得到了回答。

在评论部分与/来自 Vencat 的讨论和建议导致我有其他问题,但我想应该在一个新问题中讨论这些问题。

于 2019-04-18T09:46:20.827 回答