打开摄像头
bool CameraCapture::open(const QString& deviceName)
{
m_avFrame = av_frame_alloc();
AVInputFormat *inputFormat = av_find_input_format("dshow");
AVDictionary *format_opts = nullptr;
//av_dict_set_int(&format_opts, "rtbufsize", 3041280 * 10, 0);
av_dict_set(&format_opts, "avioflags", "direct", 0);
av_dict_set(&format_opts, "video_size", "1280x720", 0);
av_dict_set(&format_opts, "framerate", "30", 0);
av_dict_set(&format_opts, "vcodec", "mjpeg", 0);
m_pFormatContent = avformat_alloc_context();
QString urlString = QString("video=") + deviceName;
// 打开输入
int result = avformat_open_input(&m_pFormatContent, urlString.toLocal8Bit().data(), inputFormat, &format_opts);
if (result < 0)
{
qDebug() << "AVFormat Open Input Error!";
return false;
}
result = avformat_find_stream_info(m_pFormatContent, nullptr);
if (result < 0)
{
qDebug() << "AVFormat Find Stream Info Error!";
return false;
}
// find Video Stream Index
int count = m_pFormatContent->nb_streams;
for (int i=0; i<count; ++i)
{
if (m_pFormatContent->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
m_nVideoStreamIndex = i;
break;
}
}
if (m_nVideoStreamIndex < 0)
return false;
// 查找解码器
m_pCaptureContext = m_pFormatContent->streams[m_nVideoStreamIndex]->codec;
AVCodec* codec = avcodec_find_decoder(m_pCaptureContext->codec_id);
if (codec == nullptr)
return false;
// 打开解码器
if (avcodec_open2(m_pCaptureContext, codec, nullptr) != 0)
return false;
// 设置尺寸、格式等信息
m_pCameraData.m_nWidth = m_pCaptureContext->width;
m_pCameraData.m_nHeight = m_pCaptureContext->height;
AVPixelFormat format = m_pCaptureContext->pix_fmt;
format = convertDeprecatedFormat(format);
if (m_isUsedSwsScale)
return true;
m_isUsedSwsScale = false;
if (format == AV_PIX_FMT_YUV420P)
m_pCameraData.m_pixelFormat = CameraData::PIXFORMAT_YUV420P;
else if (format == AV_PIX_FMT_YUV422P)
m_pCameraData.m_pixelFormat = CameraData::PIXFORMAT_YUV422P;
else if (format == AV_PIX_FMT_YUV444P)
m_pCameraData.m_pixelFormat = CameraData::PIXFORMAT_YUV444P;
else {
m_pCameraData.m_pixelFormat = CameraData::PIXFORMAT_RGB24;
m_isUsedSwsScale = true;
}
return true;
}
AVPixelFormat CameraCapture::convertDeprecatedFormat(enum AVPixelFormat format)
{
switch (format)
{
case AV_PIX_FMT_YUVJ420P:
return AV_PIX_FMT_YUV420P;
case AV_PIX_FMT_YUVJ422P:
return AV_PIX_FMT_YUV422P;
case AV_PIX_FMT_YUVJ444P:
return AV_PIX_FMT_YUV444P;
case AV_PIX_FMT_YUVJ440P:
return AV_PIX_FMT_YUV440P;
default:
return format;
}
}
void CameraCapture::disposeYUVData(void)
{
QMutexLocker locker(&m_pMutex);
m_pCameraData.m_cameraData.clear();
AVPixelFormat pixFormat = convertDeprecatedFormat((AVPixelFormat)m_avFrame->format);
// 设置Y的数据
if (m_avFrame->linesize[0] == m_avFrame->width)
{
m_pCameraData.m_cameraData.append((char*)m_avFrame->data[0], \
m_avFrame->linesize[0] * m_avFrame->height);
}
else
{
for (int i=0; i<m_avFrame->height; ++i)
{
m_pCameraData.m_cameraData.append((char*)m_avFrame->data[0], m_avFrame->width);
}
}
// 设置U的数据
int uDataWidth = m_avFrame->width;
int uDataHeight = m_avFrame->height;
if (pixFormat == AV_PIX_FMT_YUV420P)
{
uDataWidth = uDataWidth / 2;
uDataHeight = uDataHeight / 2;
}
else if (pixFormat == AV_PIX_FMT_YUV422P)
uDataWidth = uDataWidth / 2;
if (m_avFrame->linesize[1] == uDataWidth)
{
m_pCameraData.m_cameraData.append((char*)m_avFrame->data[1], \
m_avFrame->linesize[1] * uDataHeight);
}
else
{
for (int i=0; i<uDataHeight; ++i)
{
m_pCameraData.m_cameraData.append((char*)m_avFrame->data[1], uDataWidth);
}
}
// 设置V的数据
int vDataWidth = uDataWidth;
int vDataHeight = uDataHeight;
if (m_avFrame->linesize[1] == vDataWidth)
{
m_pCameraData.m_cameraData.append((char*)m_avFrame->data[2], \
m_avFrame->linesize[2] * vDataHeight);
}
else
{
for (int i=0; i<vDataHeight; ++i)
{
m_pCameraData.m_cameraData.append((char*)m_avFrame->data[2], vDataWidth);
}
}
}
void CameraCapture::frameToRgbImage(AVFrame* pDest, AVFrame* frame)
{
// 创建SWS上下文
if (m_pSwsContext == nullptr)
{
m_pSwsContext = sws_getContext(frame->width, frame->height, convertDeprecatedFormat((AVPixelFormat)(frame->format)), \
frame->width, frame->height, AV_PIX_FMT_RGB24, \
SWS_BILINEAR, nullptr, nullptr, nullptr);
}
//avpicture_fill( )
sws_scale(m_pSwsContext, frame->data, frame->linesize, 0, frame->height, \
pDest->data, pDest->linesize);
}
// 获取一帧数据
bool CameraCapture::capture(void)
{
AVPacket pkt;
// 获取一帧数据
int result = av_read_frame(m_pFormatContent, &pkt);
if (result)
return false;
if (pkt.stream_index != m_nVideoStreamIndex)
{
av_packet_unref(&pkt);
return false;
}
// 解码视频数据
result = avcodec_send_packet(m_pCaptureContext, &pkt);
if (result)
{
av_packet_unref(&pkt);
return false;
}
result = avcodec_receive_frame(m_pCaptureContext, m_avFrame);
if (result)
{
av_packet_unref(&pkt);
return false;
}
// 转换成RGB24
if (m_isUsedSwsScale)
{
// 设置RGBFrame
if (m_pRGBFrame == nullptr)
{
m_pRGBFrame = av_frame_alloc();
m_pRGBFrame->width = m_avFrame->width;
m_pRGBFrame->height = m_avFrame->height;
m_pRGBFrame->linesize[0] = m_pRGBFrame->width * m_pRGBFrame->height * 3;
av_image_alloc(m_pRGBFrame->data, m_pRGBFrame->linesize,
m_pRGBFrame->width, m_pRGBFrame->height, AV_PIX_FMT_RGB24, 1);
}
// 转化为RGB24
frameToRgbImage(m_pRGBFrame, m_avFrame);
// 设置数据
m_pMutex.lock();
m_pCameraData.m_cameraData.clear();
m_pCameraData.m_cameraData.append((char*)m_pRGBFrame->data[0], \
m_pRGBFrame->width * m_pRGBFrame->height * 3);
m_pCameraData.m_pixelFormat = CameraData::PIXFORMAT_RGB24;
m_pMutex.unlock();
}
else
{
disposeYUVData();
}
av_packet_unref(&pkt);
return true;
}