|
Packit |
1244b8 |
/*
|
|
Packit |
1244b8 |
* Copyright (C) 2014 Intel Corporation. All rights reserved.
|
|
Packit |
1244b8 |
*
|
|
Packit |
1244b8 |
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
Packit |
1244b8 |
* you may not use this file except in compliance with the License.
|
|
Packit |
1244b8 |
* You may obtain a copy of the License at
|
|
Packit |
1244b8 |
*
|
|
Packit |
1244b8 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
1244b8 |
*
|
|
Packit |
1244b8 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
1244b8 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
1244b8 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
1244b8 |
* See the License for the specific language governing permissions and
|
|
Packit |
1244b8 |
* limitations under the License.
|
|
Packit |
1244b8 |
*/
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
1244b8 |
#include "config.h"
|
|
Packit |
1244b8 |
#endif
|
|
Packit |
1244b8 |
#include <linux/videodev2.h>
|
|
Packit |
1244b8 |
#include <unistd.h>
|
|
Packit |
1244b8 |
#include <errno.h>
|
|
Packit |
1244b8 |
#include <stdlib.h>
|
|
Packit |
1244b8 |
#include <sys/mman.h>
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
#include "v4l2_encode.h"
|
|
Packit |
1244b8 |
#include "VideoEncoderHost.h"
|
|
Packit |
1244b8 |
#include "common/log.h"
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
V4l2Encoder::V4l2Encoder()
|
|
Packit |
1244b8 |
: m_videoParamsChanged(false)
|
|
Packit |
1244b8 |
, m_maxOutputBufferSize(0)
|
|
Packit |
1244b8 |
, m_outputBufferSpace(NULL)
|
|
Packit |
1244b8 |
, m_separatedStreamHeader(false)
|
|
Packit |
1244b8 |
, m_requestStreamHeader(true)
|
|
Packit |
1244b8 |
, m_forceKeyFrame(false)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
m_memoryMode[INPUT] = V4L2_MEMORY_USERPTR; // dma_buf hasn't been supported yet
|
|
Packit |
1244b8 |
m_pixelFormat[INPUT] = V4L2_PIX_FMT_YUV420M;
|
|
Packit |
1244b8 |
m_bufferPlaneCount[INPUT] = 3; // decided by m_pixelFormat[INPUT]
|
|
Packit |
1244b8 |
m_memoryMode[OUTPUT] = V4L2_MEMORY_MMAP;
|
|
Packit |
1244b8 |
m_pixelFormat[OUTPUT] = V4L2_PIX_FMT_H264;
|
|
Packit |
1244b8 |
m_bufferPlaneCount[OUTPUT] = 1;
|
|
Packit |
1244b8 |
m_maxBufferCount[INPUT] = 3;
|
|
Packit |
1244b8 |
m_maxBufferCount[OUTPUT] = 3;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
m_inputFrames.resize(m_maxBufferCount[INPUT]);
|
|
Packit |
1244b8 |
m_outputFrames.resize(m_maxBufferCount[OUTPUT]);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Encoder::start()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
YamiStatus status = YAMI_SUCCESS;
|
|
Packit |
1244b8 |
ASSERT(m_encoder);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
VideoConfigAVCStreamFormat streamFormat;
|
|
Packit |
1244b8 |
streamFormat.size = sizeof(VideoConfigAVCStreamFormat);
|
|
Packit |
1244b8 |
streamFormat.streamFormat = AVC_STREAM_FORMAT_ANNEXB;
|
|
Packit |
1244b8 |
m_encoder->setParameters(VideoConfigTypeAVCStreamFormat, &streamFormat);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (m_svct) {
|
|
Packit |
1244b8 |
VideoTemporalLayers layers;
|
|
Packit |
1244b8 |
layers.numLayersMinus1 = 1; // It is two layers actually
|
|
Packit |
1244b8 |
layers.bitRate[0] = m_videoParams.rcParams.bitRate / 2;
|
|
Packit |
1244b8 |
layers.bitRate[1] = m_videoParams.rcParams.bitRate;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
m_videoParams.temporalLayers = layers;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
status = m_encoder->setParameters(VideoParamsTypeCommon, &m_videoParams);
|
|
Packit |
1244b8 |
ASSERT(status == YAMI_SUCCESS);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
NativeDisplay nativeDisplay;
|
|
Packit |
1244b8 |
nativeDisplay.type = NATIVE_DISPLAY_DRM;
|
|
Packit |
1244b8 |
nativeDisplay.handle = 0;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
m_encoder->setNativeDisplay(&nativeDisplay);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
status = m_encoder->start();
|
|
Packit |
1244b8 |
ASSERT(status == YAMI_SUCCESS);
|
|
Packit |
1244b8 |
status = m_encoder->getParameters(VideoParamsTypeCommon, &m_videoParams);
|
|
Packit |
1244b8 |
ASSERT(status == YAMI_SUCCESS);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Encoder::stop()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
YamiStatus encodeStatus = YAMI_SUCCESS;
|
|
Packit |
1244b8 |
if (m_encoder)
|
|
Packit |
1244b8 |
encodeStatus = m_encoder->stop();
|
|
Packit |
1244b8 |
return encodeStatus == YAMI_SUCCESS;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Encoder::UpdateVideoParameters(bool isInputThread)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
YamiStatus status = YAMI_SUCCESS;
|
|
Packit |
1244b8 |
AutoLock locker(m_videoParamsLock); // make sure the caller has released m_videoParamsLock
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (!m_videoParamsChanged)
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (isInputThread || !m_streamOn[INPUT]) {
|
|
Packit |
1244b8 |
status = m_encoder->setParameters(VideoParamsTypeCommon, &m_videoParams);
|
|
Packit |
1244b8 |
ASSERT(status == YAMI_SUCCESS);
|
|
Packit |
1244b8 |
m_videoParamsChanged = false;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return status == YAMI_SUCCESS;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
bool V4l2Encoder::inputPulse(uint32_t index)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
YamiStatus status = YAMI_SUCCESS;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if(m_videoParamsChanged )
|
|
Packit |
1244b8 |
UpdateVideoParameters(true);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
DEBUG_FOURCC("m_inputFrames[index].fourcc: ", m_inputFrames[index].fourcc);
|
|
Packit |
1244b8 |
status = m_encoder->encode(&m_inputFrames[index]);
|
|
Packit |
1244b8 |
ASSERT(m_inputFrames[index].bufAvailable); // check it at a later time when yami does encode in async
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (status != YAMI_SUCCESS)
|
|
Packit |
1244b8 |
return false;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Encoder::outputPulse(uint32_t &index)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
YamiStatus status = YAMI_SUCCESS;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
VideoEncOutputBuffer *outputBuffer = &(m_outputFrames[index]);
|
|
Packit |
1244b8 |
if (m_separatedStreamHeader) {
|
|
Packit |
1244b8 |
outputBuffer->format = OUTPUT_FRAME_DATA;
|
|
Packit |
1244b8 |
if (m_requestStreamHeader) {
|
|
Packit |
1244b8 |
outputBuffer->format = OUTPUT_CODEC_DATA;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
} else
|
|
Packit |
1244b8 |
outputBuffer->format = OUTPUT_EVERYTHING;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
status = m_encoder->getOutput(outputBuffer, false);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (status != YAMI_SUCCESS)
|
|
Packit |
1244b8 |
return false;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
ASSERT(m_maxOutputBufferSize > 0); // update m_maxOutputBufferSize after VIDIOC_S_FMT
|
|
Packit |
1244b8 |
ASSERT(m_outputBufferSpace);
|
|
Packit |
1244b8 |
ASSERT(outputBuffer->dataSize <= m_maxOutputBufferSize);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (m_separatedStreamHeader) {
|
|
Packit |
1244b8 |
if (m_requestStreamHeader)
|
|
Packit |
1244b8 |
m_requestStreamHeader = false;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Encoder::acceptInputBuffer(struct v4l2_buffer *qbuf)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
uint32_t i;
|
|
Packit |
1244b8 |
VideoEncRawBuffer *inputBuffer = &(m_inputFrames[qbuf->index]);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
// XXX todo: add multiple planes support for yami
|
|
Packit |
1244b8 |
inputBuffer->data = reinterpret_cast<uint8_t*>(qbuf->m.planes[0].m.userptr);
|
|
Packit |
1244b8 |
inputBuffer->size = 0;
|
|
Packit |
1244b8 |
for (i=0; i<qbuf->length; i++) {
|
|
Packit |
1244b8 |
inputBuffer->size += qbuf->m.planes[i].bytesused;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
inputBuffer->bufAvailable = false;
|
|
Packit |
1244b8 |
DEBUG("qbuf->index: %d, inputBuffer: %p, bufAvailable: %d", qbuf->index, inputBuffer, inputBuffer->bufAvailable);
|
|
Packit |
1244b8 |
inputBuffer->timeStamp = qbuf->timestamp.tv_sec * 1000000 + qbuf->timestamp.tv_usec; // XXX
|
|
Packit |
1244b8 |
if (m_forceKeyFrame) {
|
|
Packit |
1244b8 |
inputBuffer->forceKeyFrame = true;
|
|
Packit |
1244b8 |
m_forceKeyFrame = false;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
switch(m_pixelFormat[INPUT]) {
|
|
Packit |
1244b8 |
case V4L2_PIX_FMT_NV12:
|
|
Packit |
1244b8 |
inputBuffer->fourcc = VA_FOURCC_NV12;
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case V4L2_PIX_FMT_YUV420M:
|
|
Packit |
1244b8 |
inputBuffer->fourcc = VA_FOURCC('I', '4', '2', '0');
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case V4L2_PIX_FMT_YUYV:
|
|
Packit |
1244b8 |
inputBuffer->fourcc = VA_FOURCC_YUY2;
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
default:
|
|
Packit |
1244b8 |
ASSERT(0);
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Encoder::giveOutputBuffer(struct v4l2_buffer *dqbuf)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
ASSERT(dqbuf->index < m_maxBufferCount[OUTPUT]);
|
|
Packit |
1244b8 |
VideoEncOutputBuffer *outputBuffer = &(m_outputFrames[dqbuf->index]);
|
|
Packit |
1244b8 |
dqbuf->m.planes[0].bytesused = outputBuffer->dataSize;
|
|
Packit |
1244b8 |
dqbuf->bytesused = m_outputFrames[dqbuf->index].dataSize;
|
|
Packit |
1244b8 |
dqbuf->m.planes[0].m.mem_offset = 0;
|
|
Packit |
1244b8 |
ASSERT(m_maxOutputBufferSize > 0);
|
|
Packit |
1244b8 |
ASSERT(m_outputBufferSpace);
|
|
Packit |
1244b8 |
if (outputBuffer->flag & ENCODE_BUFFERFLAG_SYNCFRAME)
|
|
Packit |
1244b8 |
dqbuf->flags = V4L2_BUF_FLAG_KEYFRAME;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (m_svct && (m_videoParams.temporalLayers.numLayersMinus1 > 0)
|
|
Packit |
1244b8 |
&& (outputBuffer->temporalID == m_videoParams.temporalLayers.numLayersMinus1)) {
|
|
Packit |
1244b8 |
dqbuf->flags |= V4L2_BUF_FLAG_NON_REF;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Encoder::ioctl(int command, void* arg)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
YamiStatus encodeStatus = YAMI_SUCCESS;
|
|
Packit |
1244b8 |
int32_t ret = 0;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
DEBUG("fd: %d, ioctl command: %s", m_fd[0], IoctlCommandString(command));
|
|
Packit |
1244b8 |
switch (command) {
|
|
Packit |
1244b8 |
case VIDIOC_QBUF:
|
|
Packit |
1244b8 |
case VIDIOC_QUERYCAP:
|
|
Packit |
1244b8 |
case VIDIOC_STREAMON:
|
|
Packit |
1244b8 |
case VIDIOC_STREAMOFF:
|
|
Packit |
1244b8 |
case VIDIOC_REQBUFS:
|
|
Packit |
1244b8 |
case VIDIOC_DQBUF:
|
|
Packit |
1244b8 |
ret = V4l2CodecBase::ioctl(command, arg);
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case VIDIOC_QUERYBUF: {
|
|
Packit |
1244b8 |
struct v4l2_buffer *buffer = static_cast<struct v4l2_buffer*>(arg);
|
|
Packit |
1244b8 |
ASSERT (buffer->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
|
|
Packit |
1244b8 |
ASSERT(buffer->memory == V4L2_MEMORY_MMAP);
|
|
Packit |
1244b8 |
ASSERT(buffer->index < m_maxBufferCount[OUTPUT]);
|
|
Packit |
1244b8 |
ASSERT(buffer->length == m_bufferPlaneCount[OUTPUT]);
|
|
Packit |
1244b8 |
ASSERT(m_maxOutputBufferSize > 0);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
buffer->m.planes[0].length = m_maxOutputBufferSize;
|
|
Packit |
1244b8 |
buffer->m.planes[0].m.mem_offset = m_maxOutputBufferSize * buffer->index;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case VIDIOC_S_EXT_CTRLS: {
|
|
Packit |
1244b8 |
uint32_t i;
|
|
Packit |
1244b8 |
struct v4l2_ext_controls *control = static_cast<struct v4l2_ext_controls *>(arg);
|
|
Packit |
1244b8 |
DEBUG("V4L2_CTRL_CLASS_MPEG: %d, control->ctrl_class: %d", V4L2_CTRL_CLASS_MPEG, control->ctrl_class);
|
|
Packit |
1244b8 |
if (control->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
|
|
Packit |
1244b8 |
AutoLock locker(m_videoParamsLock);
|
|
Packit |
1244b8 |
struct v4l2_ext_control *ctrls = control->controls;
|
|
Packit |
1244b8 |
DEBUG("control->count: %d", control->count);
|
|
Packit |
1244b8 |
for (i=0; i<control->count; i++) {
|
|
Packit |
1244b8 |
DEBUG("VIDIOC_S_EXT_CTRLS:V4L2_CTRL_CLASS_MPEG:%d", ctrls->id);
|
|
Packit |
1244b8 |
switch (ctrls->id) {
|
|
Packit |
1244b8 |
case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
|
|
Packit |
1244b8 |
// ::EncodeTask
|
|
Packit |
1244b8 |
ASSERT(ctrls->value == V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME);
|
|
Packit |
1244b8 |
m_forceKeyFrame = true;
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case V4L2_CID_MPEG_VIDEO_BITRATE: {
|
|
Packit |
1244b8 |
// ::RequestEncodingParametersChangeTask
|
|
Packit |
1244b8 |
m_videoParams.rcParams.bitRate = ctrls->value;
|
|
Packit |
1244b8 |
m_videoParamsChanged = true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
|
|
Packit |
1244b8 |
INFO("enable bitrate control");
|
|
Packit |
1244b8 |
m_videoParams.rcMode = RATE_CONTROL_CBR;
|
|
Packit |
1244b8 |
m_videoParamsChanged = true;
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
|
|
Packit |
1244b8 |
// Separate stream header so we can cache it and insert into the stream.
|
|
Packit |
1244b8 |
if (ctrls->value == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE)
|
|
Packit |
1244b8 |
m_separatedStreamHeader = true;
|
|
Packit |
1244b8 |
INFO("use separated stream header: %d", m_separatedStreamHeader);
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case V4L2_CID_MPEG_VIDEO_B_FRAMES:
|
|
Packit |
1244b8 |
case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF:
|
|
Packit |
1244b8 |
case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT:
|
|
Packit |
1244b8 |
case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
|
|
Packit |
1244b8 |
case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
|
|
Packit |
1244b8 |
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
|
|
Packit |
1244b8 |
case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
|
|
Packit |
1244b8 |
default:
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
ctrls++;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
UpdateVideoParameters();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case VIDIOC_S_PARM: {
|
|
Packit |
1244b8 |
struct v4l2_streamparm *parms = static_cast<struct v4l2_streamparm *>(arg);
|
|
Packit |
1244b8 |
if (parms->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
Packit |
1244b8 |
AutoLock locker(m_videoParamsLock);
|
|
Packit |
1244b8 |
// ::RequestEncodingParametersChangeTask
|
|
Packit |
1244b8 |
m_videoParams.frameRate.frameRateNum = parms->parm.output.timeperframe.numerator;
|
|
Packit |
1244b8 |
m_videoParams.frameRate.frameRateDenom = parms->parm.output.timeperframe.denominator;
|
|
Packit |
1244b8 |
uint32_t framerate = m_videoParams.frameRate.frameRateNum/m_videoParams.frameRate.frameRateDenom;
|
|
Packit |
1244b8 |
if (framerate * 2 < m_videoParams.intraPeriod) {
|
|
Packit |
1244b8 |
m_videoParams.intraPeriod = framerate * 2;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
m_videoParamsChanged = true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
UpdateVideoParameters();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case VIDIOC_S_FMT: {
|
|
Packit |
1244b8 |
struct v4l2_format *format = static_cast<struct v4l2_format *>(arg);
|
|
Packit |
1244b8 |
ASSERT(!m_streamOn[INPUT] && !m_streamOn[OUTPUT]);
|
|
Packit |
1244b8 |
if (format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
|
Packit |
1244b8 |
// ::SetOutputFormat
|
|
Packit |
1244b8 |
switch (format->fmt.pix_mp.pixelformat) {
|
|
Packit |
1244b8 |
case V4L2_PIX_FMT_H264: {
|
|
Packit |
1244b8 |
m_encoder.reset(createVideoEncoder(YAMI_MIME_H264), releaseVideoEncoder);
|
|
Packit |
1244b8 |
if (!m_encoder) {
|
|
Packit |
1244b8 |
ret = -1;
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
m_videoParams.size = sizeof(m_videoParams);
|
|
Packit |
1244b8 |
encodeStatus = m_encoder->getParameters(VideoParamsTypeCommon, &m_videoParams);
|
|
Packit |
1244b8 |
ASSERT(encodeStatus == YAMI_SUCCESS);
|
|
Packit |
1244b8 |
m_videoParams.profile = VAProfileH264Main;
|
|
Packit |
1244b8 |
encodeStatus = m_encoder->setParameters(VideoParamsTypeCommon, &m_videoParams);
|
|
Packit |
1244b8 |
ASSERT(encodeStatus == YAMI_SUCCESS);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case V4L2_PIX_FMT_VP8:
|
|
Packit |
1244b8 |
default:
|
|
Packit |
1244b8 |
ret = -1;
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
} else if (format->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
Packit |
1244b8 |
// ::NegotiateInputFormat
|
|
Packit |
1244b8 |
ASSERT(format->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_YUV420M
|
|
Packit |
1244b8 |
|| format->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_YUYV
|
|
Packit |
1244b8 |
|| format->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_NV12);
|
|
Packit |
1244b8 |
m_pixelFormat[INPUT] = format->fmt.pix_mp.pixelformat;
|
|
Packit |
1244b8 |
switch (m_pixelFormat[INPUT]) {
|
|
Packit |
1244b8 |
case V4L2_PIX_FMT_YUV420M:
|
|
Packit |
1244b8 |
m_bufferPlaneCount[INPUT] = 3;
|
|
Packit |
1244b8 |
format->fmt.pix_mp.plane_fmt[0].bytesperline = m_videoParams.resolution.width;
|
|
Packit |
1244b8 |
format->fmt.pix_mp.plane_fmt[0].sizeimage = m_videoParams.resolution.width * m_videoParams.resolution.height;
|
|
Packit |
1244b8 |
format->fmt.pix_mp.plane_fmt[1].bytesperline = m_videoParams.resolution.width/2;
|
|
Packit |
1244b8 |
format->fmt.pix_mp.plane_fmt[1].sizeimage = m_videoParams.resolution.width * m_videoParams.resolution.height /4;
|
|
Packit |
1244b8 |
format->fmt.pix_mp.plane_fmt[2].bytesperline = m_videoParams.resolution.width/2;
|
|
Packit |
1244b8 |
format->fmt.pix_mp.plane_fmt[2].sizeimage = m_videoParams.resolution.width * m_videoParams.resolution.height /4;
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case V4L2_PIX_FMT_NV12:
|
|
Packit |
1244b8 |
m_bufferPlaneCount[INPUT] = 2;
|
|
Packit |
1244b8 |
format->fmt.pix_mp.plane_fmt[0].bytesperline = m_videoParams.resolution.width;
|
|
Packit |
1244b8 |
format->fmt.pix_mp.plane_fmt[0].sizeimage = m_videoParams.resolution.width * m_videoParams.resolution.height;
|
|
Packit |
1244b8 |
format->fmt.pix_mp.plane_fmt[1].bytesperline = m_videoParams.resolution.width;
|
|
Packit |
1244b8 |
format->fmt.pix_mp.plane_fmt[1].sizeimage = m_videoParams.resolution.width * m_videoParams.resolution.height /2;
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case V4L2_PIX_FMT_YUYV:
|
|
Packit |
1244b8 |
m_bufferPlaneCount[INPUT] = 1;
|
|
Packit |
1244b8 |
format->fmt.pix_mp.plane_fmt[0].bytesperline = m_videoParams.resolution.width * 2;
|
|
Packit |
1244b8 |
format->fmt.pix_mp.plane_fmt[0].sizeimage = m_videoParams.resolution.width * m_videoParams.resolution.height * 2;
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
default:
|
|
Packit |
1244b8 |
ASSERT(0);
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
ASSERT(m_encoder);
|
|
Packit |
1244b8 |
m_videoParams.resolution.width = format->fmt.pix_mp.width;
|
|
Packit |
1244b8 |
m_videoParams.resolution.height= format->fmt.pix_mp.height;
|
|
Packit |
1244b8 |
encodeStatus = m_encoder->setParameters(VideoParamsTypeCommon, &m_videoParams);
|
|
Packit |
1244b8 |
ASSERT(encodeStatus == YAMI_SUCCESS);
|
|
Packit |
1244b8 |
encodeStatus = m_encoder->getMaxOutSize(&m_maxOutputBufferSize);
|
|
Packit |
1244b8 |
ASSERT(encodeStatus == YAMI_SUCCESS);
|
|
Packit |
1244b8 |
INFO("resolution: %d x %d, m_maxOutputBufferSize: %d", m_videoParams.resolution.width,
|
|
Packit |
1244b8 |
m_videoParams.resolution.height, m_maxOutputBufferSize);
|
|
Packit |
1244b8 |
} else {
|
|
Packit |
1244b8 |
ret = -1;
|
|
Packit |
1244b8 |
ERROR("unknow type: %d of setting format VIDIOC_S_FMT", format->type);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
case VIDIOC_S_CROP: {
|
|
Packit |
1244b8 |
// ::SetFormats
|
|
Packit |
1244b8 |
//struct v4l2_crop *crop = static_cast<struct v4l2_crop *>(arg);
|
|
Packit |
1244b8 |
INFO("ignore crop for now (the difference between buffer size and real size)");
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
default:
|
|
Packit |
1244b8 |
ret = -1;
|
|
Packit |
1244b8 |
ERROR("unknown ioctrl command: %d", command);
|
|
Packit |
1244b8 |
break;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (ret == -1 && errno != EAGAIN) {
|
|
Packit |
1244b8 |
ERROR("ioctl failed");
|
|
Packit |
1244b8 |
WARNING("ioctl command: %s failed", IoctlCommandString(command));
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return ret;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void* V4l2Encoder::mmap (void* addr, size_t length,
|
|
Packit |
1244b8 |
int prot, int flags, unsigned int offset)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
uint32_t i;
|
|
Packit |
1244b8 |
ASSERT((prot == PROT_READ) | PROT_WRITE);
|
|
Packit |
1244b8 |
ASSERT(flags == MAP_SHARED);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
ASSERT(m_maxOutputBufferSize > 0);
|
|
Packit |
1244b8 |
ASSERT(length <= m_maxOutputBufferSize);
|
|
Packit |
1244b8 |
if (!m_outputBufferSpace) {
|
|
Packit |
1244b8 |
m_outputBufferSpace = static_cast<uint8_t*>(malloc(m_maxOutputBufferSize * m_maxBufferCount[OUTPUT]));
|
|
Packit |
1244b8 |
for (i=0; i
|
|
Packit |
1244b8 |
m_outputFrames[i].data = m_outputBufferSpace + m_maxOutputBufferSize*i;
|
|
Packit |
1244b8 |
m_outputFrames[i].bufferSize = m_maxOutputBufferSize;
|
|
Packit |
1244b8 |
m_outputFrames[i].format = OUTPUT_EVERYTHING;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
ASSERT(m_outputBufferSpace);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return m_outputBufferSpace + offset;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|