如果您不需要跨平台功能 Video for Windows (VFW) API 是一个不错的选择 ( http://msdn.microsoft.com/en-us/library/windows/desktop/dd756808(v=vs.85).aspx ),我不会放一个完整的代码块,因为有很多事情要做,但你应该能够从参考链接中弄清楚。基本上,您执行 a ,然后通过withAVIFileOpen
获取视频流,或者使用 立即执行,然后使用. 如果你到了失败的地步,我可以尝试提供帮助,但这应该很简单。AVIFileGetStream
streamtypeVIDEO
AVIStreamOpenFromFile
AVIStreamRead
另外,不知道为什么 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 将为您省去空帧的麻烦,并且只提供那些包含数据的样本。