我正在尝试使用libav解码MJPEG流。流来自V4L2驱动程序。使用高分辨率时,以下代码可以正常工作。但是,当使用低分辨率(例如320x190)时,会产生奇怪的伪像
void V4L2::compressedCapturingThread(){
const AVCodec *codec=avcodec_find_decoder(m_currVidMode.codec.toAVCodecID());
if(!codec)
return; //Something went horribly wrong
//Allocate the context
AVCodecContext* codecCtx=avcodec_alloc_context3(codec);
if(!codecCtx){
return; //Error
}
codecCtx->width=m_currVidMode.res.width;
codecCtx->height=m_currVidMode.res.height;
//Open the context
if (avcodec_open2(codecCtx, codec, nullptr) < 0) {
avcodec_free_context(&codecCtx);
return;
}
//Allocate space for the packet
AVPacket *pkt=av_packet_alloc();
if(!pkt){
avcodec_free_context(&codecCtx);
return;
}
AVFrame* decodedFrame=av_frame_alloc();
if(!decodedFrame){
avcodec_free_context(&codecCtx);
avcodec_free_context(&codecCtx);
return;
}
Graphics::Uploader uplo;
v4l2_buffer buf;
int ret;
Utils::ImageBuffer decodedImgBuf(
Utils::ImageAttributes(
m_currVidMode.res,
m_currVidMode.pixFmt
), (u_int8_t*)nullptr
);
//Main loop
while(!m_threadExit){
reqBuffer(&buf);
if(!buf.bytesused){
continue;
}
//Create the packet with the given data
u_int8_t* bufData=(u_int8_t*)av_malloc(buf.bytesused);
memcpy(bufData, m_buffers[buf.index].buffer, buf.bytesused); //copy the data
av_packet_from_data (pkt, bufData, buf.bytesused);
freeBuffer(&buf); //V4L2 buffer no longer needed
//Try to decode the packet
ret=avcodec_send_packet(codecCtx, pkt);
av_packet_unref(pkt);
if(ret<0){
continue;
}
ret = avcodec_receive_frame(codecCtx, decodedFrame);
if(ret<0){
continue;
}
memcpy(decodedImgBuf.data, decodedFrame->data, sizeof(decodedImgBuf.data)); //Copy plane pointers
if(decodedImgBuf.att.pixFmt == Utils::PixelFormats::NONE){
decodedImgBuf.att.pixFmt=Utils::PixelFormat(codecCtx->pix_fmt);
//Change deprecated formats
if(decodedImgBuf.att.pixFmt == Utils::PixelFormats::YUVJ420P)
decodedImgBuf.att.pixFmt = Utils::PixelFormats::YUV420P;
else if(decodedImgBuf.att.pixFmt == Utils::PixelFormats::YUVJ422P)
decodedImgBuf.att.pixFmt = Utils::PixelFormats::YUV422P;
else if(decodedImgBuf.att.pixFmt == Utils::PixelFormats::YUVJ440P)
decodedImgBuf.att.pixFmt = Utils::PixelFormats::YUV440P;
else if(decodedImgBuf.att.pixFmt == Utils::PixelFormats::YUVJ444P)
decodedImgBuf.att.pixFmt = Utils::PixelFormats::YUV444P;
}
std::unique_ptr<const Graphics::Frame> frame;
{
Graphics::UniqueContext ctx(Graphics::Context::getAvalibleCtx());
frame=uplo.getFrame(decodedImgBuf);
}
Stream::AsyncSource<Graphics::Frame>::push(std::move(frame));
}
//Free everything
avcodec_free_context(&codecCtx);
av_packet_free(&pkt);
av_frame_free(&decodedFrame);
}
如果我尝试在avcodec_receive_frame()
之后立即将AVFrame的内容读取到磁盘上,则会得到上述“奇怪的结果”(我将其上传到rawpixels.net看到了),因此问题不在此行之后。如果我在freeBuffer()
之前将pkt的数据以JPEG格式保存到磁盘,则可以正确看到该图像。我要附上图片
完整的代码可以在以下位置找到:
https://github.com/oierlauzi/zuazo
https://github.com/oierlauzi/zuazo/blob/master/src/Zuazo/Sources/V4L2.cpp
编辑1: 我忘了提一下,codecCtx-> pix_fmt的值为AL_PIX_FMT_YUVJ422P(由libav提供)