How to read YUV8 data from avi file?
我有一个avi文件,其中包含未压缩的灰色视频数据。我需要从中提取帧。文件大小为22 Gb。
我该怎么做?
我已经尝试过ffmpeg,但是它给我"找不到视频流的编解码器参数"消息-因为工作中没有编解码器,只有帧。
由于Opencv仅使用ffmpeg读取视频,因此也排除了opencv。
似乎剩下的唯一路径是尝试挖掘原始数据,但我不知道如何。
编辑:这是我使用opencv从文件中读取的代码。该故障发生在第二个if内。在文件上运行ffmpeg二进制文件也失败,并显示上述消息(找不到编解码器Aprameters等)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* 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\ ", 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\ "); ret = 1; goto end; } |
编辑:
这是我尝试提取的示例代码:pastebin。每次调用AVIStreamRead后,我得到的结果都是不变的缓冲区。
如果不需要跨平台功能,则Windows Video(VFW)API是一个不错的选择(http://msdn.microsoft.com/zh-cn/library/windows/desktop/dd756808(v=vs.85 ).aspx),因为有很多事情要做,所以我不会放置整个代码块,但是您应该能够从参考链接中找出来。基本上,您执行
此外,不确定ffmpeg为何失败,我一直在使用ffmpeg进行原始AVI读取,而没有涉及任何编解码器,您可以发布对ffpeg的调用实际上失败吗?
编辑:
对于读取的数据大小为0时出现的问题。AVI文件每秒具有N个用于帧的插槽,其中N是视频的fps。在现实生活中,采样不会以这种速度精确地到达(例如IP监控摄像机),因此实际数据采样索引可能是非连续的,例如1,5,11,...,并且VFW会在它们之间插入空采样(即从中读取零尺寸的样本)。您要做的是调用
1 2 3 4 5 6 7 8 9 10 11 12 13 | ... 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示例,以使其解析相同的文件(由于缺少错误检查,因此代码质量很抱歉,但是我想您可以请参阅逻辑流程):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | /* 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\ ", 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\ "); 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\ ", packet->pts); av_free_packet(packet); } |
基本上,您打开上下文并从中读取数据包。您将同时获得音频和视频数据包,因此应检查该数据包是否属于感兴趣的流。 FFMPEG将为您节省空白帧的麻烦,并且仅提供其中包含数据的那些样本。