QtMultimedia. Qt 5.1. QVideoFrame converting in another struct
-
Hi, all.
I need to create h264 stream from camera. Unfortunately, QVideoProbe::setSource( some_QMediaRecorder ) always return false (both in Windows and Linux) and I can't get already encoded frames.
I inherit QAbstractVideoSurface, make QCamera::setViewFinder for my class and now I give all QVideoFrame's from camera in YUV420P format. I need to encode its and will use x264. For encoding I should convert QVideoFrame into x264_image_t.@typedef struct
{
int i_csp; /* Colorspace /
int i_plane; / Number of image planes /
int i_stride[4]; / Strides for each plane */
uint8_t plane[4]; / Pointers to each plane */
} x264_image_t;@Does the QVideoFrame::bits() method return pointer to plain buffer, contains all plains of picture? How I can convert it? x264 expects YUV420P and I need just copy frame.
-
[quote author="jmimi" date="1387821006"]Hi
I have the same problem.
Do you find any solution?[/quote]Yes. I use avpicture_fill(...) for copy QVideoFrame into AVPicture and sws_scale(...) for converting this picture into x_264_picture_t with YUV420P colorspace.
@void H264Encoder::encodeFrame(const QVideoFrame& frame)
{
if (!frame.isReadable() || !frame.isMapped())
return;
//m_in_pixel_format = avcodec::AV_PIX_FMT_RGB32;
if (m_in_pixel_format == PIX_FMT_NONE)
{
if ( !this->set_pix_fmt(frame) )
return;
}size_t in_width = frame.width();
size_t in_height = frame.height();if (!m_sws_ctx)
{
m_sws_ctx = sws_getContext(in_width, in_height, m_in_pixel_format,
m_out_width, m_out_height, m_out_pixel_format, SWS_FAST_BILINEAR, NULL, NULL, NULL);
if (!m_sws_ctx)
{
qDebug() << "libswscale: Error creating sws context!";
return;
}
}//copy frame from QVideoFrame into m_pic_raw
int bytes_copied = avpicture_fill(&m_pic_raw, const_cast<uint8_t*>(frame.bits()),
m_in_pixel_format, in_width, in_height);if (bytes_copied < 0)
{
qDebug() << "H264Encoder: error calling avpicture_fill(...)!";
return;
}//convert img into m_out_format and save in m_in_pic
int scaled_img_height = sws_scale(m_sws_ctx, m_pic_raw.data, m_pic_raw.linesize, 0, in_height,
m_in_pic->img.plane, m_in_pic->img.i_stride);if ( scaled_img_height < 0 || (size_t)scaled_img_height != m_out_height )
{
qDebug() << "Scaling failed!";
return;
}m_in_pic->i_pts = m_pts++;
int res = x264_encoder_encode(m_encoder, &m_nals, &m_num_nals, m_in_pic, m_out_pic);
if (res < 0)
{
qDebug() << "x264_encode error!";
return;
}m_last_frame_sz = res;
//create frame_t for every NAL unit
std::vector<Frame_t> result;
this->get_encoded_frame(result);
for (auto i = result.cbegin(); i != result.cend(); i++)
{
SharedEncodedFrame shared_result;
shared_result << *i;
emit newEncodedFrame(shared_result);
}
}bool H264Encoder::get_encoded_frame( std::vector<Frame_t>& buf )const
{
if (!m_last_frame_sz)
return false;buf.clear();
buf.resize(m_num_nals);for (int i = 0; i < m_num_nals; i++)
{
std::copy((const char*)m_nals[i].p_payload + 4, (const char*)m_nals[i].p_payload +
m_nals[i].i_payload, std::back_inserter(buf[i]));
}return true;
}
@where I have next members:
@x264_param_t* m_params;x264_t* m_encoder;
x264_picture_t *m_in_pic, *m_out_pic;
PixelFormat m_in_pixel_format;
PixelFormat m_out_pixel_format;size_t m_out_height;
size_t m_out_width;size_t m_fps;
//input frame;
AVPicture m_pic_raw;x264_nal_t* m_nals;
int m_num_nals;
size_t m_last_frame_sz;int m_pts;
SwsContext* m_sws_ctx;@