我有OpenCV::Mat
类型的彩色jpeg图片,我使用avcodec
从他们创建视频。我得到的视频是颠倒的,黑色和白色,每帧的每一行都移动了,我得到了对角线。这样的输出可能是什么原因?
按照this链接观看我使用avcodec获取的视频。
我正在使用acpicture_fill
函数从avFrame
框架创建cv::Mat
!
P.S。
每个cv :: Mat cvFrame的宽度= 810,高度= 610,步长= 2432
我注意到avFrame(由acpicture_fill填充)有linesize[0]=2430
我尝试手动设置avFrame->linesizep0]=2432
而不是2430,但它仍然没有帮助。
========代码=================================== ======================
AVCodec *encoder = avcodec_find_encoder(AV_CODEC_ID_H264);
AVStream *outStream = avformat_new_stream(outContainer, encoder);
avcodec_get_context_defaults3(outStream->codec, encoder);
outStream->codec->pix_fmt = AV_PIX_FMT_YUV420P;
outStream->codec->width = 810;
outStream->codec->height = 610;
//...
SwsContext *swsCtx = sws_getContext(outStream->codec->width, outStream->codec->height, PIX_FMT_RGB24,
outStream->codec->width, outStream->codec->height, outStream->codec->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
for (uint i=0; i < frameNums; i++)
{
// get frame at location I using OpenCV
cv::Mat cvFrame;
myReader.getFrame(cvFrame, i);
cv::Size frameSize = cvFrame.size();
//Each cv::Mat cvFrame has width=810, height=610, step=2432
1. // create AVPicture from cv::Mat frame
2. avpicture_fill((AVPicture*)avFrame, cvFrame.data, PIX_FMT_RGB24, outStream->codec->width, outStream->codec->height);
3avFrame->width = frameSize.width;
4. avFrame->height = frameSize.height;
// rescale to outStream format
sws_scale(swsCtx, avFrame->data, avFrame->linesize, 0, outStream->codec->height, avFrameRescaledFrame->data, avFrameRescaledFrame ->linesize);
encoderRescaledFrame->pts=i;
avFrameRescaledFrame->width = frameSize.width;
avFrameRescaledFrame->height = frameSize.height;
av_init_packet(&avEncodedPacket);
avEncodedPacket.data = NULL;
avEncodedPacket.size = 0;
// encode rescaled frame
if(avcodec_encode_video2(outStream->codec, &avEncodedPacket, avFrameRescaledFrame, &got_frame) < 0) exit(1);
if(got_frame)
{
if (avEncodedPacket.pts != AV_NOPTS_VALUE)
avEncodedPacket.pts = av_rescale_q(avEncodedPacket.pts, outStream->codec->time_base, outStream->time_base);
if (avEncodedPacket.dts != AV_NOPTS_VALUE)
avEncodedPacket.dts = av_rescale_q(avEncodedPacket.dts, outStream->codec->time_base, outStream->time_base);
// outContainer is "mp4"
av_write_frame(outContainer, & avEncodedPacket);
av_free_packet(&encodedPacket);
}
}
已更新
正如@Alex建议我用下面的代码改变了第1-4行
int width = frameSize.width, height = frameSize.height;
avpicture_alloc((AVPicture*)avFrame, AV_PIX_FMT_RGB24, outStream->codec->width, outStream->codec->height);
for (int h = 0; h < height; h++)
{
memcpy(&(avFrame->data[0][h*avFrame->linesize[0]]), &(cvFrame.data[h*cvFrame.step]), width*3);
}
我现在获得的视频(here)几乎是完美的。这不是颠倒的,不是黑色和白色,但似乎缺少一个RGB组件。每种棕色/红色都变成蓝色(在原始图像中应该是反之亦然)。
可能是什么问题呢?可以重新调整(sws_scale
)到AV_PIX_FMT_YUV420P
格式会导致这个吗?
答案 0 :(得分:2)
问题简而言之:avpicture_fill()
期望行之间没有填充,即步幅(步长)等于width*sizeof(pixel)
,即810 * 3 = 2430.数据的实际跨度cv :: Mat step就像你说的那样是2432,这是不同的,所以直接传递数据是行不通的。没有办法告诉avpicture_fill()
对输入数据使用不同的步幅;它不是API的一部分(你可能会说它应该是:)
有两种可能的解决方案:
创建一个数组,其中输入数据是连续的,行之间没有填充。您必须将cv :: Mat中的每一行记忆复制到该数组中。然后将其传递给avpicture_fill()
。
int width, height; // get from mat
uint8_t* buf = malloc(width * height * 3); // 3 bytes per pixel
for (int i = 0; i < height; i++)
{
memcpy( &( buf[ i*width*3 ] ), &( mat->data[ i*mat->step ] ), width*3 );
}
avpicture_fill(..., buf, ...)
顺便说一句,要垂直翻转视频,您可以将最后一行复制到第一行,依此类推:
...
memcpy( &( buf[ i*width*3 ] ), &( mat->data[ (height - i - 1)*mat->step ] ), width*3 );
...
或者,自己填写AVPicture:
AVPicture* pic = malloc(sizeof(AVPicture));
avpicture_alloc(pic, PIX_FMT_BGR24, width, height);
for (int i = 0; i < height; i++)
{
memcpy( &( pic->data[0][ i*pic->linesize[0] ] ), &( mat->data[ i*mat->step ] ), width*3);
}
无需分配pic-> data [0]或设置pic-&gt; linesize [0],avpicture_alloc()应该这样做。也没有必要填写数据[1]或数据[2],那些应该是空的。
编辑:删除旧代码,显示将R,G,B复制到单独的平面。 PIX_FMT_BGR24不是平面格式。
我不熟悉OpenCV C ++ API来弄清楚如何获得宽度和高度(显然不是mat宽度),但我想你知道我的意思。
P.S。顺便说一句,您的视频实际上黑白。只是每个连续的行偏移两个字节,因此颜色会旋转:红色变为绿色,绿色变为蓝色,依此类推。结果是灰度等级,但如果仔细观察,各行都会被着色。
答案 1 :(得分:0)
您是否考虑过使用OpenCV's features为您制作视频?由于您的数据已存储在cv::Mat
中,因此更加容易。
如果您想保留自己的方法,可以rotate the cv::Mat
。
答案 2 :(得分:0)
关于原始帖子的UPDATE中的颜色问题。这是由,
引起的OpenCV Mat是(BGR) - &gt; FFmpeg AVFrame是(RGB)?
如果是,请尝试
cvtColor( cvFrame , cvFrame , CV_BGR2RGB ) ;
在第1行之前。