1

我有 avi 文件,其中包含未压缩的灰色视频数据。我需要从中提取帧。文件大小为 22 Gb。

我怎么做?

我已经尝试过 ffmpeg,但它给了我“找不到视频流的编解码器参数”消息 - 因为没有编解码器在工作,只有帧。

由于 Opencv 仅使用 ffmpeg 读取视频,因此也排除了 opencv。

似乎剩下的唯一途径是尝试挖掘原始数据,但我不知道如何。

编辑:这是我用opencv从文件中读取的代码。失败发生在第二个 if 内。在文件上运行 ffmpeg 二进制文件也会失败并显示上述消息(找不到编解码器参数等)

/* register all formats and codecs */
av_register_all();

/* open input file, and allocate format context */
if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
    fprintf(stderr, "Could not open source file %s\n", src_filename);
    ret = 1;
    goto end;
}
fmt_ctx->seek2any = true;
/* retrieve stream information */
int res = avformat_find_stream_info(fmt_ctx, NULL);
if (res < 0) {
    fprintf(stderr, "Could not find stream information\n");
    ret = 1;
    goto end;
}

编辑:

这是我尝试进行提取的示例代码:pastebin。我得到的结果是每次调用 AVIStreamRead 后缓冲区不变。

4

1 回答 1

2

如果您不需要跨平台功能 Video for Windows (VFW) API 是一个不错的选择 ( http://msdn.microsoft.com/en-us/library/windows/desktop/dd756808(v=vs.85).aspx ),我不会放一个完整的代码块,因为有很多事情要做,但你应该能够从参考链接中弄清楚。基本上,您执行 a ,然后通过withAVIFileOpen获取视频流,或者使用 立即执行,然后使用. 如果你到了失败的地步,我可以尝试提供帮助,但这应该很简单。AVIFileGetStreamstreamtypeVIDEOAVIStreamOpenFromFileAVIStreamRead

另外,不知道为什么 ffmpeg 失败了,我一直在用 ffmpeg 进行原始 AVI 读取,没有涉及任何编解码器,你能发布对 ffpeg 的调用实际上失败了吗?

编辑:

对于您在读取数据大小为 0 时看到的问题。AVI 文件每秒有 N 个帧插槽,其中 N 是视频的 fps。在现实生活中,样本不会完全以那个速度出现(例如 IP 监控摄像头),因此实际数据样本索引可能是不连续的,如 1、5、11,......并且 VFW 会在它们之间插入空样本(即从您读取大小为零的样本的位置)。您需要做的是AVIStreamRead使用 NULL 作为缓冲区和 0 作为大小调用,直到bRead不是 0 或者您运行过去的最后一个样本。当您获得实际大小时,您可以再次AVIStreamRead使用缓冲区指针和大小调用该样本索引。我通常做压缩视频,所以我不使用建议的大小,但至少根据你的代码片段,我会做这样的事情:

...
bRead = 0;
do 
{
    aviOpRes = AVIStreamRead(ppavi,smpS,1,NULL,0,&bRead,&smpN);
} while (bRead == 0 && ++smpS < si.dwLength + si.dwStart);
if(smpS >= si.dwLength + si.dwStart)
    break;
PUCHAR tempBuffer = new UCHAR[bRead];
aviOpRes = AVIStreamRead(ppavi,smpS,1,tempBuffer,bRead,&bRead,&smpN);
/* do whatever you need */
delete tempBuffer;
...

编辑2:

由于这对某人或您自己在 VFW 和 FFMPEG 之间做出选择可能会派上用场,我还更新了您的 FFMPEG 示例,以便它解析相同的文件(抱歉代码质量,因为它缺少错误检查,但我想您可以看到合乎逻辑的流动):

/* register all formats and codecs */
av_register_all();
AVFormatContext* fmt_ctx = NULL;
/* open input file, and allocate format context */
const char *src_filename = "E:\\Output.avi";
if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
    fprintf(stderr, "Could not open source file %s\n", src_filename);
    abort();
}
/* retrieve stream information */
int res = avformat_find_stream_info(fmt_ctx, NULL);
if (res < 0) {
    fprintf(stderr, "Could not find stream information\n");
    abort();
}
int video_stream_index = 0; /* video stream is usualy 0 but still better to lookup in case it's not present */
for(; video_stream_index < fmt_ctx->nb_streams; ++video_stream_index)
{
    if(fmt_ctx->streams[video_stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        break;
}
if(video_stream_index == fmt_ctx->nb_streams)
    abort();
AVPacket *packet = new AVPacket;
while(av_read_frame(fmt_ctx, packet) == 0)
{
    if (packet->stream_index == video_stream_index)
        printf("Sample nr %d\n", packet->pts);
    av_free_packet(packet);
}

基本上你打开上下文并从中读取数据包。您将同时获得音频和视频数据包,因此您应该检查数据包是否属于感兴趣的流。FFMPEG 将为您省去空帧的麻烦,并且只提供那些包含数据的样本。

于 2013-09-03T11:47:22.443 回答