我正在尝试用C ++编写代码以解码来自内存的视频流。我知道我必须使用AVIOContext并实现读取和查找功能才能使其正常工作。但是就我而言,我仍然得到
未指定像素格式
尝试读取框架时出错。
#include <stdio.h>
#include <windows.h>
#include <iostream>
#include <fstream>
using namespace std;
extern "C"
{
#include <libavformat\avformat.h>
#include <libavcodec\avcodec.h>
#include <libswscale/swscale.h>
}
static int ReadFunc(void* opaque, uint8_t* buf, int buf_size) {
auto& stream = *reinterpret_cast<istream*>(opaque);
auto bufPtr = reinterpret_cast<char*>(buf);
stream.read(bufPtr, buf_size);
auto readBytes = stream.gcount();
return readBytes;
}
static int64_t SeekFunc(void *opaque, int64_t offset, int whence) {
auto& me = *reinterpret_cast<istream*>(opaque);
switch (whence) {
case SEEK_SET:
me.seekg(offset, me.beg);
break;
case SEEK_CUR:
offset += me.tellg();
me.seekg(offset, me.beg);
break;
case SEEK_END:
me.seekg(offset, me.end);
break;
case (AVSEEK_SIZE):
int64_t currentOffset = me.tellg();
me.seekg(0, ios::end);
long size = me.tellg();
me.seekg(currentOffset, me.beg);
return size;
}
auto pos = me.tellg();
return pos;
}
int main()
{
int err;
av_register_all();
ifstream stream("c:\\temp\\file.mp4", ios::binary);
const int iBufSize = 32768;
const shared_ptr<unsigned char> buffer(reinterpret_cast<unsigned char*>(av_malloc(iBufSize)), &av_free);
auto bufferPtr = buffer.get();
const shared_ptr<AVIOContext> avioContext(avio_alloc_context(pBuffer, iBufSize, 0, reinterpret_cast<void*>(static_cast<istream*>(&stream)), &ReadFunc, nullptr, &SeekFunc), &av_free);
const auto avFormat = shared_ptr<AVFormatContext>(avformat_alloc_context(), &avformat_free_context);
auto avFormatPtr = avFormat.get();
avFormat->pb = avioContext.get();
/* This code simply crashes, not sure if it's needed
stream.read(reinterpret_cast<char*>(bufferPtr), iBufSize);
ULONG bytesRead = stream.gcount();
stream.seekg(0, stream.beg);
AVProbeData probeData;
probeData.buf = bufferPtr;
probeData.buf_size = bytesRead;
probeData.filename = "";
avFormatPtr->iformat = av_probe_input_format(&probeData, 1); */
avFormat->flags = AVFMT_FLAG_CUSTOM_IO;
avformat_open_input(&avFormatPtr, "", nullptr, nullptr);
err = avformat_find_stream_info(avFormatPtr, NULL);
if (err < 0) {
fprintf(stderr, "ffmpeg: Unable to find stream info\n");
return -1;
}
int vid_stream;
for (vid_stream = 0; vid_stream < avFormatPtr->nb_streams; ++vid_stream)
{
if (avFormatPtr->streams[vid_stream]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
break;
}
}
if (vid_stream == avFormatPtr->nb_streams)
{
fprintf(stderr, "ffmpeg: Unable to find video stream\n");
return -1;
}
AVCodecContext* codec_context = avFormatPtr->streams[vid_stream]->codec;
AVCodec* codec = avcodec_find_decoder(codec_context->codec_id);
err = avcodec_open2(codec_context, codec, NULL);
if (err < 0) {
fprintf(stderr, "ffmpeg: Unable to open codec\n");
return -1;
}
// init frame
AVFrame* frame = av_frame_alloc();
frame = av_frame_alloc();
if (!frame)
{
av_log(NULL, AV_LOG_ERROR, "Cannot init frame\n");
}
//init packet
AVPacket *pkt = NULL;
pkt = av_packet_alloc();
av_init_packet(pkt);
if (!pkt)
{
av_log(NULL, AV_LOG_ERROR, "Cannot init packet\n");
}
/*avFormatPtr->max_analyze_duration = INT64_MAX;
avFormatPtr->probesize = INT64_MAX;*/
while (av_read_frame(avFormatPtr, pkt) >= 0) {
if (pkt->stream_index == vid_stream) {
// Video stream packet
int frame_finished;
avcodec_decode_video2(codec_context, frame, &frame_finished, pkt);
if (frame_finished)
{
// FRAME DECODED
}
}
av_free_packet(pkt);
}
// Free the YUV frame
av_free(frame);
// Close the codec
avcodec_close(codec_context);
// Close the video file
avformat_close_input(&avFormatPtr);
return 0;
}
类似的question已经存在。解决的办法是添加我执行的搜索功能。我是否正确实现了Seek函数?它的行为很奇怪,有时要求的偏移量是-1。我的代码和此问题的代码示例之间的主要区别是,在我的情况下使用的是istream而不是FILE对象,但是我是C ++的新手,所以好像我缺少一些东西。