|
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 |
|
|
Packit |
1244b8 |
#define __STDC_FORMAT_MACROS
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
#include <inttypes.h>
|
|
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 |
#include <string.h>
|
|
Packit |
1244b8 |
#include <vector>
|
|
Packit |
1244b8 |
#include <map>
|
|
Packit |
1244b8 |
#include <deque>
|
|
Packit |
1244b8 |
#include <set>
|
|
Packit |
1244b8 |
#include <va/va_drmcommon.h>
|
|
Packit |
1244b8 |
#if defined(__ENABLE_WAYLAND__)
|
|
Packit |
1244b8 |
#include <va/va_wayland.h>
|
|
Packit |
1244b8 |
#endif
|
|
Packit |
1244b8 |
#include "v4l2_decode.h"
|
|
Packit |
1244b8 |
#include "VideoDecoderHost.h"
|
|
Packit |
1244b8 |
#include "common/log.h"
|
|
Packit |
1244b8 |
#include "common/common_def.h"
|
|
Packit |
1244b8 |
#include "common/basesurfaceallocator.h"
|
|
Packit |
1244b8 |
#include "vaapi/vaapidisplay.h"
|
|
Packit |
1244b8 |
#include "vaapi/VaapiUtils.h"
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
#define INT64_TO_TIMEVAL(i64, time_val) \
|
|
Packit |
1244b8 |
do { \
|
|
Packit |
1244b8 |
time_val.tv_sec = (int32_t)(i64 >> 31); \
|
|
Packit |
1244b8 |
time_val.tv_usec = (int32_t)(i64 & 0x7fffffff); \
|
|
Packit |
1244b8 |
} while (0)
|
|
Packit |
1244b8 |
#define TIMEVAL_TO_INT64(i64, time_val) \
|
|
Packit |
1244b8 |
do { \
|
|
Packit |
1244b8 |
i64 = time_val.tv_sec; \
|
|
Packit |
1244b8 |
i64 = (i64 << 31) + time_val.tv_usec; \
|
|
Packit |
1244b8 |
} while (0)
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
//return if we have error
|
|
Packit |
1244b8 |
#define ERROR_RETURN(no) \
|
|
Packit |
1244b8 |
do { \
|
|
Packit |
1244b8 |
if (no) { \
|
|
Packit |
1244b8 |
errno = no; \
|
|
Packit |
1244b8 |
return -1; \
|
|
Packit |
1244b8 |
} \
|
|
Packit |
1244b8 |
} while (0)
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
#define CHECK(cond) \
|
|
Packit |
1244b8 |
do { \
|
|
Packit |
1244b8 |
if (!(cond)) { \
|
|
Packit |
1244b8 |
ERROR("%s is false", #cond); \
|
|
Packit |
1244b8 |
ERROR_RETURN(EINVAL); \
|
|
Packit |
1244b8 |
} \
|
|
Packit |
1244b8 |
} while (0)
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
//check condition in post messsage.
|
|
Packit |
1244b8 |
#define PCHECK(cond) \
|
|
Packit |
1244b8 |
do { \
|
|
Packit |
1244b8 |
if (!(cond)) { \
|
|
Packit |
1244b8 |
m_state = kError; \
|
|
Packit |
1244b8 |
ERROR("%s is false", #cond); \
|
|
Packit |
1244b8 |
return; \
|
|
Packit |
1244b8 |
} \
|
|
Packit |
1244b8 |
} while (0)
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
#define SEND(func) \
|
|
Packit |
1244b8 |
do { \
|
|
Packit |
1244b8 |
int32_t ret_ = sendTask(func); \
|
|
Packit |
1244b8 |
ERROR_RETURN(ret_); \
|
|
Packit |
1244b8 |
} while (0)
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
const static uint32_t kDefaultInputSize = 1024 * 1024;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
//#undef DEBUG
|
|
Packit |
1244b8 |
//#define DEBUG ERROR
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
using namespace std;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
struct FrameInfo {
|
|
Packit |
1244b8 |
int64_t timeStamp;
|
|
Packit |
1244b8 |
};
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
class V4l2Decoder::Output {
|
|
Packit |
1244b8 |
public:
|
|
Packit |
1244b8 |
Output(V4l2Decoder* decoder)
|
|
Packit |
1244b8 |
: m_decoder(decoder)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
memset(&m_lastFormat, 0, sizeof(m_lastFormat));
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual void setDecodeAllocator(DecoderPtr decoder)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
/* nothing */
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual int32_t requestBuffers(uint32_t count) = 0;
|
|
Packit |
1244b8 |
virtual void output(SharedPtr<VideoFrame>& frame) = 0;
|
|
Packit |
1244b8 |
virtual bool isAllocationDone() = 0;
|
|
Packit |
1244b8 |
virtual bool isOutputReady() = 0;
|
|
Packit |
1244b8 |
virtual int32_t deque(struct v4l2_buffer* buf) = 0;
|
|
Packit |
1244b8 |
virtual int32_t queue(struct v4l2_buffer* buf)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
m_decoder->m_out.queue(buf->index);
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual int32_t createBuffers(struct v4l2_create_buffers* createBuffers)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual void streamOff()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
//nothing for base
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
void flush()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
//forget pending format change on flush
|
|
Packit |
1244b8 |
m_pendingFormat.reset();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool setFormat(const VideoFormatInfo* format)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
DEBUG("last format = %dx%dx%d@%x",
|
|
Packit |
1244b8 |
m_lastFormat.surfaceWidth, m_lastFormat.surfaceHeight,
|
|
Packit |
1244b8 |
m_lastFormat.surfaceNumber, m_lastFormat.fourcc);
|
|
Packit |
1244b8 |
if (m_pendingFormat) {
|
|
Packit |
1244b8 |
DEBUG("pending format = %dx%dx%d@%x",
|
|
Packit |
1244b8 |
m_pendingFormat->surfaceWidth, m_pendingFormat->surfaceHeight,
|
|
Packit |
1244b8 |
m_pendingFormat->surfaceNumber, m_pendingFormat->fourcc);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
bool changed = m_lastFormat.surfaceWidth != format->surfaceWidth
|
|
Packit |
1244b8 |
|| m_lastFormat.surfaceHeight != format->surfaceHeight
|
|
Packit |
1244b8 |
|| m_lastFormat.surfaceNumber != format->surfaceNumber
|
|
Packit |
1244b8 |
|| m_lastFormat.fourcc != format->fourcc;
|
|
Packit |
1244b8 |
if (changed) {
|
|
Packit |
1244b8 |
DEBUG("format changed to %dx%dx%d@%x",
|
|
Packit |
1244b8 |
format->surfaceWidth, format->surfaceHeight,
|
|
Packit |
1244b8 |
format->surfaceNumber, format->fourcc);
|
|
Packit |
1244b8 |
m_pendingFormat.reset(new VideoFormatInfo);
|
|
Packit |
1244b8 |
*m_pendingFormat = *format;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
return changed;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
protected:
|
|
Packit |
1244b8 |
void requestFrameInfo(uint32_t count)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
m_frameInfo.resize(count);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
void outputFrame(uint32_t index, SharedPtr<VideoFrame>& frame)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
setTimeStamp(index, frame->timeStamp);
|
|
Packit |
1244b8 |
m_decoder->m_out.put(index);
|
|
Packit |
1244b8 |
m_decoder->setDeviceEvent(0);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
void getTimeStamp(uint32_t index, struct timeval& timeStamp)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
DEBUG("index = %d, size = %d", (int)index, (int)m_frameInfo.size());
|
|
Packit |
1244b8 |
ASSERT(index < m_frameInfo.size());
|
|
Packit |
1244b8 |
INT64_TO_TIMEVAL(m_frameInfo[index].timeStamp, timeStamp);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
void setTimeStamp(uint32_t index, int64_t timeStamp)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
ASSERT(index < m_frameInfo.size());
|
|
Packit |
1244b8 |
m_frameInfo[index].timeStamp = timeStamp;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void getBufferInfo(struct v4l2_buffer* buf, uint32_t index)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
buf->index = index;
|
|
Packit |
1244b8 |
//chrome will use this value.
|
|
Packit |
1244b8 |
buf->m.planes[0].bytesused = 1;
|
|
Packit |
1244b8 |
buf->m.planes[1].bytesused = 1;
|
|
Packit |
1244b8 |
getTimeStamp(index, buf->timestamp);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void finishFormatChangeIfNeeded()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
DEBUG("m_pendingFormat = %d", !!m_pendingFormat);
|
|
Packit |
1244b8 |
if (m_pendingFormat) {
|
|
Packit |
1244b8 |
m_lastFormat = *m_pendingFormat;
|
|
Packit |
1244b8 |
m_pendingFormat.reset();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
V4l2Decoder* m_decoder;
|
|
Packit |
1244b8 |
vector<FrameInfo> m_frameInfo;
|
|
Packit |
1244b8 |
Lock m_lock;
|
|
Packit |
1244b8 |
VideoFormatInfo m_lastFormat;
|
|
Packit |
1244b8 |
//format changed but caller did not allocate buffer for us.
|
|
Packit |
1244b8 |
SharedPtr<VideoFormatInfo> m_pendingFormat;
|
|
Packit |
1244b8 |
};
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
class SurfaceGetter {
|
|
Packit |
1244b8 |
typedef map<intptr_t, uint32_t> UsedMap;
|
|
Packit |
1244b8 |
const static uint32_t kHoldByRenderer = 1;
|
|
Packit |
1244b8 |
const static uint32_t kHoldByDecoder = 2;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
public:
|
|
Packit |
1244b8 |
static YamiStatus getSurface(SurfaceAllocParams* param, intptr_t* surface)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
SurfaceGetter* p = (SurfaceGetter*)param->user;
|
|
Packit |
1244b8 |
return p->getSurface(surface);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
static YamiStatus putSurface(SurfaceAllocParams* param, intptr_t surface)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
SurfaceGetter* p = (SurfaceGetter*)param->user;
|
|
Packit |
1244b8 |
return p->putSurface(surface);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
YamiStatus getSurface(intptr_t* surface)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
AutoLock l(m_lock);
|
|
Packit |
1244b8 |
if (!takeOneFree(surface, kHoldByDecoder))
|
|
Packit |
1244b8 |
return YAMI_DECODE_NO_SURFACE;
|
|
Packit |
1244b8 |
DEBUG("getSurface: %x", (uint32_t)*surface);
|
|
Packit |
1244b8 |
return YAMI_SUCCESS;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
YamiStatus putSurface(intptr_t surface)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
AutoLock l(m_lock);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
clearFlag(surface, kHoldByDecoder);
|
|
Packit |
1244b8 |
DEBUG("putSurface: %x", (uint32_t)surface);
|
|
Packit |
1244b8 |
return YAMI_SUCCESS;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool holdByRenderer(intptr_t surface)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
AutoLock l(m_lock);
|
|
Packit |
1244b8 |
return setFlag(surface, kHoldByRenderer);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool freeByRenderer(intptr_t surface)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
AutoLock l(m_lock);
|
|
Packit |
1244b8 |
return clearFlag(surface, kHoldByRenderer);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void holdAllByRenderer()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
DEBUG("hold all by renderer");
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
AutoLock l(m_lock);
|
|
Packit |
1244b8 |
m_freed.clear();
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
UsedMap::iterator it = m_used.begin();
|
|
Packit |
1244b8 |
while (it != m_used.end()) {
|
|
Packit |
1244b8 |
it->second = kHoldByRenderer;
|
|
Packit |
1244b8 |
++it;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool takeOneFreeByRenderer(intptr_t* surface)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
AutoLock l(m_lock);
|
|
Packit |
1244b8 |
return takeOneFree(surface, kHoldByRenderer);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
bool addNewSurface(intptr_t surface)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
AutoLock l(m_lock);
|
|
Packit |
1244b8 |
UsedMap::iterator it = m_used.find(surface);
|
|
Packit |
1244b8 |
if (it != m_used.end()) {
|
|
Packit |
1244b8 |
ERROR("add duplicate surface %x, it's hold by %s", (uint32_t)surface, getOwnerName(it->second));
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
m_freed.push_back(surface);
|
|
Packit |
1244b8 |
m_used[surface] = 0;
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void removeAllSurfaces()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
m_used.clear();
|
|
Packit |
1244b8 |
m_freed.clear();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
private:
|
|
Packit |
1244b8 |
bool takeOneFree(intptr_t* surface, uint32_t flag)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
if (m_freed.empty()) {
|
|
Packit |
1244b8 |
DEBUG("no free surface");
|
|
Packit |
1244b8 |
UsedMap::iterator it = m_used.begin();
|
|
Packit |
1244b8 |
while (it != m_used.end()) {
|
|
Packit |
1244b8 |
DEBUG("surface %x, it's hold by %s", (uint32_t)it->first, getOwnerName(it->second));
|
|
Packit |
1244b8 |
++it;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
return false;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
*surface = m_freed.front();
|
|
Packit |
1244b8 |
m_used[*surface] = flag;
|
|
Packit |
1244b8 |
m_freed.pop_front();
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool setFlag(intptr_t surface, uint32_t flag)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
UsedMap::iterator it = m_used.find(surface);
|
|
Packit |
1244b8 |
DEBUG("%s takes %x", getOwnerName(flag), (uint32_t)surface);
|
|
Packit |
1244b8 |
if (it == m_used.end()) {
|
|
Packit |
1244b8 |
ERROR("set owner to %s failed for %x", getOwnerName(flag), (uint32_t)surface);
|
|
Packit |
1244b8 |
return false;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
it->second |= flag;
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
YamiStatus clearFlag(intptr_t surface, uint32_t flag)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
UsedMap::iterator it = m_used.find(surface);
|
|
Packit |
1244b8 |
DEBUG("return %x from %s", (uint32_t)surface, getOwnerName(flag));
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (it == m_used.end()) {
|
|
Packit |
1244b8 |
ERROR("clear wrong surface id = %x", (uint32_t)surface);
|
|
Packit |
1244b8 |
return YAMI_INVALID_PARAM;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
if (!(it->second & flag)) {
|
|
Packit |
1244b8 |
ERROR("%x is not hold by %s, it hold by %s", (uint32_t)surface, getOwnerName(flag), getOwnerName(it->second));
|
|
Packit |
1244b8 |
return YAMI_INVALID_PARAM;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
it->second &= ~flag;
|
|
Packit |
1244b8 |
if (!it->second) {
|
|
Packit |
1244b8 |
m_freed.push_back(surface);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
return YAMI_SUCCESS;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
private:
|
|
Packit |
1244b8 |
const char* getOwnerName(uint32_t flag)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
if (flag == kHoldByRenderer)
|
|
Packit |
1244b8 |
return "renderer";
|
|
Packit |
1244b8 |
if (flag == kHoldByDecoder)
|
|
Packit |
1244b8 |
return "decoder";
|
|
Packit |
1244b8 |
if (flag == (kHoldByRenderer | kHoldByDecoder))
|
|
Packit |
1244b8 |
return "decoder and render";
|
|
Packit |
1244b8 |
if (!flag)
|
|
Packit |
1244b8 |
return "no one";
|
|
Packit |
1244b8 |
return "unknow";
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
Lock m_lock;
|
|
Packit |
1244b8 |
UsedMap m_used;
|
|
Packit |
1244b8 |
deque<intptr_t> m_freed;
|
|
Packit |
1244b8 |
};
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
//the buffer resource is created from V4L2's user
|
|
Packit |
1244b8 |
class ExternalBufferOutput : public V4l2Decoder::Output, BaseSurfaceAllocator {
|
|
Packit |
1244b8 |
typedef map<intptr_t, uint32_t> SurfaceMap;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
public:
|
|
Packit |
1244b8 |
ExternalBufferOutput(V4l2Decoder* decoder)
|
|
Packit |
1244b8 |
: V4l2Decoder::Output(decoder)
|
|
Packit |
1244b8 |
, m_getter(new SurfaceGetter)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual void setDecodeAllocator(DecoderPtr decoder)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
decoder->setAllocator(this);
|
|
Packit |
1244b8 |
/* nothing */
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual int32_t requestBuffers(uint32_t count)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
AutoLock l(m_lock);
|
|
Packit |
1244b8 |
m_count = count;
|
|
Packit |
1244b8 |
if (!count) {
|
|
Packit |
1244b8 |
for (size_t i = 0; i < m_surfaces.size(); i++) {
|
|
Packit |
1244b8 |
if (m_surfaces[i] != (intptr_t)VA_INVALID_SURFACE) {
|
|
Packit |
1244b8 |
destorySurface(m_surfaces[i]);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
m_getter->removeAllSurfaces();
|
|
Packit |
1244b8 |
m_surfaceMap.clear();
|
|
Packit |
1244b8 |
} else {
|
|
Packit |
1244b8 |
finishFormatChangeIfNeeded();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
m_surfaces.resize(count, VA_INVALID_SURFACE);
|
|
Packit |
1244b8 |
requestFrameInfo(count);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual void output(SharedPtr<VideoFrame>& frame)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
ASSERT(m_getter.get());
|
|
Packit |
1244b8 |
m_getter->holdByRenderer(frame->surface);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
AutoLock l(m_lock);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
SurfaceMap::iterator it = m_surfaceMap.find(frame->surface);
|
|
Packit |
1244b8 |
ASSERT(it != m_surfaceMap.end());
|
|
Packit |
1244b8 |
outputFrame(it->second, frame);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual bool isAllocationDone()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
bool ret = !m_pendingFormat && m_surfaceMap.size() == m_count;
|
|
Packit |
1244b8 |
DEBUG("is allocation done = %d, pending format = %d, size = %d, count = %d",
|
|
Packit |
1244b8 |
ret, !!m_pendingFormat, (int)m_surfaceMap.size(), m_count);
|
|
Packit |
1244b8 |
return ret;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
virtual bool isOutputReady()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
int32_t queue(struct v4l2_buffer* buf)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
uint32_t index;
|
|
Packit |
1244b8 |
bool streamOn;
|
|
Packit |
1244b8 |
//create and update index
|
|
Packit |
1244b8 |
intptr_t surface;
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
//we need hold lock in freeVideoFrame, so we keep the lock in {}
|
|
Packit |
1244b8 |
AutoLock l(m_lock);
|
|
Packit |
1244b8 |
index = buf->index;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
CHECK(index < m_surfaces.size());
|
|
Packit |
1244b8 |
streamOn = m_decoder->m_outputOn;
|
|
Packit |
1244b8 |
if (!m_decoder->m_outputOn) {
|
|
Packit |
1244b8 |
CHECK(createSurface(surface, buf));
|
|
Packit |
1244b8 |
m_surfaces[index] = surface;
|
|
Packit |
1244b8 |
m_surfaceMap[surface] = index;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
surface = m_surfaces[index];
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
ASSERT(m_getter.get());
|
|
Packit |
1244b8 |
if (!streamOn)
|
|
Packit |
1244b8 |
m_getter->addNewSurface(surface);
|
|
Packit |
1244b8 |
else
|
|
Packit |
1244b8 |
m_getter->freeByRenderer(surface);
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual int32_t deque(struct v4l2_buffer* buf)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
AutoLock l(m_lock);
|
|
Packit |
1244b8 |
uint32_t index;
|
|
Packit |
1244b8 |
if (m_decoder->m_outputOn) {
|
|
Packit |
1244b8 |
if (!m_decoder->m_out.deque(index)) {
|
|
Packit |
1244b8 |
ERROR_RETURN(EAGAIN);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
else {
|
|
Packit |
1244b8 |
CHECK(m_getter);
|
|
Packit |
1244b8 |
intptr_t p;
|
|
Packit |
1244b8 |
//this mean we need deque the surface from free list
|
|
Packit |
1244b8 |
CHECK(m_getter->takeOneFreeByRenderer(&p);;
|
|
Packit |
1244b8 |
SurfaceMap::iterator it = m_surfaceMap.find(p);
|
|
Packit |
1244b8 |
CHECK(it != m_surfaceMap.end());
|
|
Packit |
1244b8 |
index = it->second;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
getBufferInfo(buf, index);
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual void streamOff()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
m_getter->holdAllByRenderer();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
protected:
|
|
Packit |
1244b8 |
virtual YamiStatus doAlloc(SurfaceAllocParams* params)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
AutoLock l(m_lock);
|
|
Packit |
1244b8 |
if (m_surfaces.size() != m_surfaceMap.size()) {
|
|
Packit |
1244b8 |
ERROR("surfaces size did not match map size (%d != %d)", (int)m_surfaces.size(), (int)m_surfaceMap.size());
|
|
Packit |
1244b8 |
return YAMI_FAIL;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
if (params->size > m_surfaces.size()) {
|
|
Packit |
1244b8 |
DEBUG("ATTENTION!!! require size > surface size (%d > %d), m_isThumbnailMode = %d", (int)params->size, (int)m_surfaces.size(), m_decoder->m_isThumbnailMode);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
params->surfaces = &m_surfaces[0];
|
|
Packit |
1244b8 |
params->size = m_surfaces.size();
|
|
Packit |
1244b8 |
params->user = m_getter.get();
|
|
Packit |
1244b8 |
params->getSurface = SurfaceGetter::getSurface;
|
|
Packit |
1244b8 |
params->putSurface = SurfaceGetter::putSurface;
|
|
Packit |
1244b8 |
return YAMI_SUCCESS;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual YamiStatus doFree(SurfaceAllocParams* params)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
/* nothing */
|
|
Packit |
1244b8 |
return YAMI_SUCCESS;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual void doUnref()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
/* nothing */
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
virtual bool createExternalSurface(intptr_t& surface, uint32_t rtFormat, VASurfaceAttribExternalBuffers& external)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
VASurfaceAttrib attribs[2];
|
|
Packit |
1244b8 |
attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
|
|
Packit |
1244b8 |
attribs[0].type = VASurfaceAttribMemoryType;
|
|
Packit |
1244b8 |
attribs[0].value.type = VAGenericValueTypeInteger;
|
|
Packit |
1244b8 |
attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
|
|
Packit |
1244b8 |
attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
|
|
Packit |
1244b8 |
attribs[1].value.type = VAGenericValueTypePointer;
|
|
Packit |
1244b8 |
attribs[1].value.value.p = &external;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
VASurfaceID id;
|
|
Packit |
1244b8 |
VAStatus vaStatus = vaCreateSurfaces(m_decoder->m_display->getID(), rtFormat, external.width, external.height,
|
|
Packit |
1244b8 |
&id, 1, attribs, N_ELEMENTS(attribs));
|
|
Packit |
1244b8 |
if (!checkVaapiStatus(vaStatus, "vaCreateSurfaces"))
|
|
Packit |
1244b8 |
return false;
|
|
Packit |
1244b8 |
surface = static_cast<intptr_t>(id);
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
virtual bool createSurface(intptr_t& surface, struct v4l2_buffer* buf) = 0;
|
|
Packit |
1244b8 |
virtual bool destorySurface(intptr_t& surface) = 0;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
uint32_t m_count;
|
|
Packit |
1244b8 |
vector<intptr_t> m_surfaces;
|
|
Packit |
1244b8 |
SurfaceMap m_surfaceMap;
|
|
Packit |
1244b8 |
SharedPtr<SurfaceGetter> m_getter;
|
|
Packit |
1244b8 |
};
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
class ExternalDmaBufOutput : public ExternalBufferOutput {
|
|
Packit |
1244b8 |
public:
|
|
Packit |
1244b8 |
ExternalDmaBufOutput(V4l2Decoder* decoder)
|
|
Packit |
1244b8 |
: ExternalBufferOutput(decoder)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
virtual int32_t createBuffers(struct v4l2_create_buffers* createBuffers)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
m_createBuffers.reset(new v4l2_create_buffers);
|
|
Packit |
1244b8 |
*m_createBuffers = *createBuffers;
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
virtual bool createSurface(intptr_t& surface, struct v4l2_buffer* buf)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
if (!m_createBuffers) {
|
|
Packit |
1244b8 |
ERROR("you need create buffer first");
|
|
Packit |
1244b8 |
return false;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
v4l2_pix_format_mplane& format = m_createBuffers->format.fmt.pix_mp;
|
|
Packit |
1244b8 |
VASurfaceAttribExternalBuffers external;
|
|
Packit |
1244b8 |
memset(&external, 0, sizeof(external));
|
|
Packit |
1244b8 |
external.pixel_format = format.pixelformat;
|
|
Packit |
1244b8 |
uint32_t rtFormat = getRtFormat(format.pixelformat);
|
|
Packit |
1244b8 |
if (!rtFormat) {
|
|
Packit |
1244b8 |
ERROR("failed get rtformat for %.4s", (char*)&format.pixelformat);
|
|
Packit |
1244b8 |
return false;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
external.width = format.width;
|
|
Packit |
1244b8 |
external.height = format.height;
|
|
Packit |
1244b8 |
external.num_planes = format.num_planes;
|
|
Packit |
1244b8 |
for (uint32_t i = 0; i < format.num_planes; i++) {
|
|
Packit |
1244b8 |
external.pitches[i] = format.plane_fmt[i].bytesperline;
|
|
Packit |
1244b8 |
//not really right, but we use sizeimage to deliver offset
|
|
Packit |
1244b8 |
external.offsets[i] = format.plane_fmt[i].sizeimage;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
external.buffers = (uintptr_t *)&buf->m.userptr;
|
|
Packit |
1244b8 |
external.num_buffers = 1;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return createExternalSurface(surface, rtFormat, external);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual bool destorySurface(intptr_t& surface)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
VASurfaceID s = (VASurfaceID)surface;
|
|
Packit |
1244b8 |
return checkVaapiStatus(vaDestroySurfaces(m_decoder->m_display->getID(), &s, 1), "vaDestroySurfaces");
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
SharedPtr<v4l2_create_buffers> m_createBuffers;
|
|
Packit |
1244b8 |
};
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
#ifdef __ENABLE_EGL__
|
|
Packit |
1244b8 |
#include "egl/egl_vaapi_image.h"
|
|
Packit |
1244b8 |
class EglOutput : public V4l2Decoder::Output {
|
|
Packit |
1244b8 |
public:
|
|
Packit |
1244b8 |
EglOutput(V4l2Decoder* decoder, VideoDataMemoryType memory_type)
|
|
Packit |
1244b8 |
: V4l2Decoder::Output(decoder)
|
|
Packit |
1244b8 |
, m_memoryType(memory_type)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
virtual int32_t requestBuffers(uint32_t count)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
v4l2_pix_format_mplane& format = m_decoder->m_outputFormat.fmt.pix_mp;
|
|
Packit |
1244b8 |
DisplayPtr& display = m_decoder->m_display;
|
|
Packit |
1244b8 |
CHECK(bool(display));
|
|
Packit |
1244b8 |
CHECK(format.width && format.height);
|
|
Packit |
1244b8 |
m_eglVaapiImages.clear();
|
|
Packit |
1244b8 |
for (uint32_t i = 0; i < count; i++) {
|
|
Packit |
1244b8 |
SharedPtr<EglVaapiImage> image(new EglVaapiImage(display->getID(), format.width, format.height));
|
|
Packit |
1244b8 |
if (!image->init()) {
|
|
Packit |
1244b8 |
ERROR("Create egl vaapi image failed");
|
|
Packit |
1244b8 |
m_eglVaapiImages.clear();
|
|
Packit |
1244b8 |
return EINVAL;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
m_eglVaapiImages.push_back(image);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
requestFrameInfo(count);
|
|
Packit |
1244b8 |
if (count) {
|
|
Packit |
1244b8 |
finishFormatChangeIfNeeded();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
int32_t useEglImage(EGLDisplay eglDisplay, EGLContext eglContext, uint32_t bufferIndex, void* eglImage)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(m_memoryType == VIDEO_DATA_MEMORY_TYPE_DRM_NAME || m_memoryType == VIDEO_DATA_MEMORY_TYPE_DMA_BUF);
|
|
Packit |
1244b8 |
CHECK(bufferIndex < m_eglVaapiImages.size());
|
|
Packit |
1244b8 |
*(EGLImageKHR*)eglImage = m_eglVaapiImages[bufferIndex]->createEglImage(eglDisplay, eglContext, m_memoryType);
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
void output(SharedPtr<VideoFrame>& frame)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
uint32_t index;
|
|
Packit |
1244b8 |
if (!m_decoder->m_out.get(index)) {
|
|
Packit |
1244b8 |
ERROR("bug: can't get index");
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
if (!(index < m_eglVaapiImages.size())) {
|
|
Packit |
1244b8 |
ERROR("index = %d, size = %d", (int)index, (int)m_eglVaapiImages.size());
|
|
Packit |
1244b8 |
ASSERT(index < m_eglVaapiImages.size());
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
m_eglVaapiImages[index]->blt(frame);
|
|
Packit |
1244b8 |
outputFrame(index, frame);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
bool isAllocationDone()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
bool ret = !m_pendingFormat && !m_eglVaapiImages.empty();
|
|
Packit |
1244b8 |
DEBUG("is allocation done = %d, pending format = %d, is empty = %d",
|
|
Packit |
1244b8 |
ret, !!m_pendingFormat, m_eglVaapiImages.empty());
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return ret;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
bool isOutputReady()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
uint32_t index;
|
|
Packit |
1244b8 |
return m_decoder->m_out.peek(index);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t deque(struct v4l2_buffer* buf)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
uint32_t index;
|
|
Packit |
1244b8 |
if (!m_decoder->m_out.deque(index)) {
|
|
Packit |
1244b8 |
ERROR_RETURN(EAGAIN);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
getBufferInfo(buf, index);
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
private:
|
|
Packit |
1244b8 |
std::vector<SharedPtr<EglVaapiImage> > m_eglVaapiImages;
|
|
Packit |
1244b8 |
VideoDataMemoryType m_memoryType;
|
|
Packit |
1244b8 |
};
|
|
Packit |
1244b8 |
#endif
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
V4l2Decoder::V4l2Decoder()
|
|
Packit |
1244b8 |
: m_inputOn(false)
|
|
Packit |
1244b8 |
, m_outputOn(false)
|
|
Packit |
1244b8 |
, m_state(kUnStarted)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
memset(&m_inputFormat, 0, sizeof(m_inputFormat));
|
|
Packit |
1244b8 |
memset(&m_outputFormat, 0, sizeof(m_outputFormat));
|
|
Packit |
1244b8 |
m_output.reset(new ExternalDmaBufOutput(this));
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
V4l2Decoder::~V4l2Decoder()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void V4l2Decoder::releaseCodecLock(bool lockable)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Decoder::start()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
return false;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Decoder::stop()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Decoder::inputPulse(uint32_t index)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return true; // always return true for decode; simply ignored unsupported nal
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Decoder::outputPulse(uint32_t& index)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Decoder::recycleOutputBuffer(int32_t index)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
// FIXME, after we remove the extra vpp, renderDone() should come here
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Decoder::recycleInputBuffer(struct v4l2_buffer* dqbuf)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Decoder::acceptInputBuffer(struct v4l2_buffer* qbuf)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
bool V4l2Decoder::giveOutputBuffer(struct v4l2_buffer* dqbuf)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
#ifndef V4L2_PIX_FMT_VP9
|
|
Packit |
1244b8 |
#define V4L2_PIX_FMT_VP9 YAMI_FOURCC('V', 'P', '9', '0')
|
|
Packit |
1244b8 |
#endif
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::ioctl(int command, void* arg)
|
|
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 |
struct v4l2_buffer* qbuf = static_cast<struct v4l2_buffer*>(arg);
|
|
Packit |
1244b8 |
return onQueueBuffer(qbuf);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_DQBUF: {
|
|
Packit |
1244b8 |
struct v4l2_buffer* dqbuf = static_cast<struct v4l2_buffer*>(arg);
|
|
Packit |
1244b8 |
return onDequeBuffer(dqbuf);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_STREAMON: {
|
|
Packit |
1244b8 |
__u32 type = *((__u32*)arg);
|
|
Packit |
1244b8 |
return onStreamOn(type);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_STREAMOFF: {
|
|
Packit |
1244b8 |
__u32 type = *((__u32*)arg);
|
|
Packit |
1244b8 |
return onStreamOff(type);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_QUERYCAP: {
|
|
Packit |
1244b8 |
return V4l2CodecBase::ioctl(command, arg);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_REQBUFS: {
|
|
Packit |
1244b8 |
struct v4l2_requestbuffers* reqbufs = static_cast<struct v4l2_requestbuffers*>(arg);
|
|
Packit |
1244b8 |
return onRequestBuffers(reqbufs);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_S_FMT: {
|
|
Packit |
1244b8 |
struct v4l2_format* format = static_cast<struct v4l2_format*>(arg);
|
|
Packit |
1244b8 |
return onSetFormat(format);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_QUERYBUF: {
|
|
Packit |
1244b8 |
struct v4l2_buffer* buf = static_cast<struct v4l2_buffer*>(arg);
|
|
Packit |
1244b8 |
return onQueryBuffer(buf);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_SUBSCRIBE_EVENT: {
|
|
Packit |
1244b8 |
struct v4l2_event_subscription* sub = static_cast<struct v4l2_event_subscription*>(arg);
|
|
Packit |
1244b8 |
return onSubscribeEvent(sub);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_DQEVENT: {
|
|
Packit |
1244b8 |
// ::DequeueEvents
|
|
Packit |
1244b8 |
struct v4l2_event* ev = static_cast<struct v4l2_event*>(arg);
|
|
Packit |
1244b8 |
return onDequeEvent(ev);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_G_FMT: {
|
|
Packit |
1244b8 |
// ::GetFormatInfo
|
|
Packit |
1244b8 |
struct v4l2_format* format = static_cast<struct v4l2_format*>(arg);
|
|
Packit |
1244b8 |
return onGetFormat(format);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_G_CTRL: {
|
|
Packit |
1244b8 |
// ::CreateOutputBuffers
|
|
Packit |
1244b8 |
struct v4l2_control* ctrl = static_cast<struct v4l2_control*>(arg);
|
|
Packit |
1244b8 |
return onGetCtrl(ctrl);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_ENUM_FMT: {
|
|
Packit |
1244b8 |
struct v4l2_fmtdesc* fmtdesc = static_cast<struct v4l2_fmtdesc*>(arg);
|
|
Packit |
1244b8 |
return onEnumFormat(fmtdesc);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_G_CROP: {
|
|
Packit |
1244b8 |
struct v4l2_crop* crop = static_cast<struct v4l2_crop*>(arg);
|
|
Packit |
1244b8 |
return onGetCrop(crop);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
case VIDIOC_CREATE_BUFS: {
|
|
Packit |
1244b8 |
struct v4l2_create_buffers* req = static_cast<struct v4l2_create_buffers*>(arg);
|
|
Packit |
1244b8 |
return onCreateBuffers(req);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
default: {
|
|
Packit |
1244b8 |
ERROR("unknown ioctrl command: %d", command);
|
|
Packit |
1244b8 |
return -1;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
VideoDecodeBuffer* V4l2Decoder::peekInput()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
uint32_t index;
|
|
Packit |
1244b8 |
if (!m_in.peek(index))
|
|
Packit |
1244b8 |
return NULL;
|
|
Packit |
1244b8 |
ASSERT(index < m_inputFrames.size());
|
|
Packit |
1244b8 |
VideoDecodeBuffer* inputBuffer = &(m_inputFrames[index]);
|
|
Packit |
1244b8 |
return inputBuffer;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void V4l2Decoder::consumeInput()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
PCHECK(m_thread.isCurrent());
|
|
Packit |
1244b8 |
uint32_t index;
|
|
Packit |
1244b8 |
if (!m_in.get(index)) {
|
|
Packit |
1244b8 |
ERROR("bug: can't get from input");
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
m_in.put(index);
|
|
Packit |
1244b8 |
setDeviceEvent(0);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void V4l2Decoder::getInputJob()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
PCHECK(m_thread.isCurrent());
|
|
Packit |
1244b8 |
PCHECK(bool(m_decoder));
|
|
Packit |
1244b8 |
if (m_state != kGetInput) {
|
|
Packit |
1244b8 |
DEBUG("early out, state = %d", m_state);
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
VideoDecodeBuffer* inputBuffer = peekInput();
|
|
Packit |
1244b8 |
if (!inputBuffer) {
|
|
Packit |
1244b8 |
DEBUG("early out, no input buffer");
|
|
Packit |
1244b8 |
m_state = kWaitInput;
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
YamiStatus status = m_decoder->decode(inputBuffer);
|
|
Packit |
1244b8 |
DEBUG("decode %d, return %d", (int)inputBuffer->size, (int)status);
|
|
Packit |
1244b8 |
if (status == YAMI_DECODE_FORMAT_CHANGE) {
|
|
Packit |
1244b8 |
DEBUG("decoder return format change");
|
|
Packit |
1244b8 |
m_state = kFormatChanged;
|
|
Packit |
1244b8 |
//now we need this format in output.
|
|
Packit |
1244b8 |
const VideoFormatInfo* outFormat = m_decoder->getFormatInfo();
|
|
Packit |
1244b8 |
PCHECK(outFormat);
|
|
Packit |
1244b8 |
m_output->setFormat(outFormat);
|
|
Packit |
1244b8 |
//drain output
|
|
Packit |
1244b8 |
getOutputJob();
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
if (status == YAMI_DECODE_NO_SURFACE) {
|
|
Packit |
1244b8 |
if (m_output->isAllocationDone()) {
|
|
Packit |
1244b8 |
m_state = kGetOutput;
|
|
Packit |
1244b8 |
getOutputJob();
|
|
Packit |
1244b8 |
m_state = kWaitSurface;
|
|
Packit |
1244b8 |
DEBUG("early out, no surface");
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
} else {
|
|
Packit |
1244b8 |
DEBUG("need relocation");
|
|
Packit |
1244b8 |
m_state = kWaitAllocation;
|
|
Packit |
1244b8 |
setCodecEvent();
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
consumeInput();
|
|
Packit |
1244b8 |
if (!m_decoder->getFormatInfo()) {
|
|
Packit |
1244b8 |
DEBUG("need more data to detect output format");
|
|
Packit |
1244b8 |
post(bind(&V4l2Decoder::getInputJob, this));
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
m_state = kGetOutput;
|
|
Packit |
1244b8 |
post(bind(&V4l2Decoder::getOutputJob, this));
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void V4l2Decoder::inputReadyJob()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
PCHECK(m_thread.isCurrent());
|
|
Packit |
1244b8 |
if (m_state != kWaitInput) {
|
|
Packit |
1244b8 |
DEBUG("early out, state = %d", m_state);
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
m_state = kGetInput;
|
|
Packit |
1244b8 |
getInputJob();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void V4l2Decoder::getOutputJob()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
PCHECK(m_thread.isCurrent());
|
|
Packit |
1244b8 |
PCHECK(bool(m_decoder));
|
|
Packit |
1244b8 |
if (m_state != kGetOutput && m_state != kFormatChanged) {
|
|
Packit |
1244b8 |
DEBUG("early out, state = %d, change = %d", m_state, kFormatChanged);
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
while (m_output->isOutputReady()) {
|
|
Packit |
1244b8 |
SharedPtr<VideoFrame> frame = m_decoder->getOutput();
|
|
Packit |
1244b8 |
if (!frame) {
|
|
Packit |
1244b8 |
if (m_state == kFormatChanged && !m_output->isAllocationDone()) {
|
|
Packit |
1244b8 |
DEBUG("need relocation");
|
|
Packit |
1244b8 |
m_state = kWaitAllocation;
|
|
Packit |
1244b8 |
setCodecEvent();
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
} else {
|
|
Packit |
1244b8 |
DEBUG("early out, no frame");
|
|
Packit |
1244b8 |
m_state = kGetInput;
|
|
Packit |
1244b8 |
post(bind(&V4l2Decoder::getInputJob, this));
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
m_output->output(frame);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
if (m_state == kGetOutput) {
|
|
Packit |
1244b8 |
m_state = kWaitOutput;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
else {
|
|
Packit |
1244b8 |
ASSERT(m_state == kFormatChanged);
|
|
Packit |
1244b8 |
DEBUG("format change, wait more output buffers");
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void V4l2Decoder::outputReadyJob()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
PCHECK(m_thread.isCurrent());
|
|
Packit |
1244b8 |
if (m_state == kWaitOutput) {
|
|
Packit |
1244b8 |
m_state = kGetOutput;
|
|
Packit |
1244b8 |
getOutputJob();
|
|
Packit |
1244b8 |
} else if (m_state == kFormatChanged) {
|
|
Packit |
1244b8 |
//try to drain output
|
|
Packit |
1244b8 |
getOutputJob();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
else if (m_state == kWaitSurface) {
|
|
Packit |
1244b8 |
m_state = kGetInput;
|
|
Packit |
1244b8 |
getInputJob();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void V4l2Decoder::checkAllocationJob()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
PCHECK(m_thread.isCurrent());
|
|
Packit |
1244b8 |
if (m_state == kWaitAllocation) {
|
|
Packit |
1244b8 |
if (m_output->isAllocationDone()) {
|
|
Packit |
1244b8 |
m_state = kGetInput;
|
|
Packit |
1244b8 |
getInputJob();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onQueueBuffer(v4l2_buffer* buf)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(buf);
|
|
Packit |
1244b8 |
uint32_t type = buf->type;
|
|
Packit |
1244b8 |
CHECK(type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
|
|
Packit |
1244b8 |
|| type == (unsigned int)V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
Packit |
1244b8 |
CHECK(buf->memory == V4L2_MEMORY_MMAP);
|
|
Packit |
1244b8 |
CHECK(buf->length == 1);
|
|
Packit |
1244b8 |
CHECK(buf->index < m_inputFrames.size());
|
|
Packit |
1244b8 |
DEBUG("queue input size = %d", buf->m.planes[0].bytesused);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
VideoDecodeBuffer& inputBuffer = m_inputFrames[buf->index];
|
|
Packit |
1244b8 |
inputBuffer.size = buf->m.planes[0].bytesused; // one plane only
|
|
Packit |
1244b8 |
if (!inputBuffer.size) // EOS
|
|
Packit |
1244b8 |
inputBuffer.data = NULL;
|
|
Packit |
1244b8 |
TIMEVAL_TO_INT64(inputBuffer.timeStamp, buf->timestamp);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
m_in.queue(buf->index);
|
|
Packit |
1244b8 |
post(bind(&V4l2Decoder::inputReadyJob, this));
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
DEBUG("queue output index = %d", buf->index);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
m_output->queue(buf);
|
|
Packit |
1244b8 |
post(bind(&V4l2Decoder::outputReadyJob, this));
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onDequeBuffer(v4l2_buffer* buf)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(buf);
|
|
Packit |
1244b8 |
uint32_t type = buf->type;
|
|
Packit |
1244b8 |
CHECK(type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
|
|
Packit |
1244b8 |
|| type == (unsigned int)V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
|
|
Packit |
1244b8 |
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
Packit |
1244b8 |
CHECK(m_inputOn);
|
|
Packit |
1244b8 |
uint32_t index;
|
|
Packit |
1244b8 |
if (!m_in.deque(index)) {
|
|
Packit |
1244b8 |
ERROR_RETURN(EAGAIN);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
buf->index = index;
|
|
Packit |
1244b8 |
DEBUG("dequeue input index = %d", buf->index);
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t ret = m_output->deque(buf);
|
|
Packit |
1244b8 |
if (!ret)
|
|
Packit |
1244b8 |
DEBUG("dequeue output index = %d", buf->index);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return ret;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onStreamOn(uint32_t type)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
|
|
Packit |
1244b8 |
|| type == (unsigned int)V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (!m_display) {
|
|
Packit |
1244b8 |
m_display = VaapiDisplay::create(m_nativeDisplay);
|
|
Packit |
1244b8 |
CHECK(bool(m_display));
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
CHECK(!m_inputOn);
|
|
Packit |
1244b8 |
m_inputOn = true;
|
|
Packit |
1244b8 |
CHECK(m_thread.start());
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
post(bind(&V4l2Decoder::startDecoderJob, this));
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
CHECK(!m_outputOn);
|
|
Packit |
1244b8 |
m_outputOn = true;
|
|
Packit |
1244b8 |
post(bind(&V4l2Decoder::checkAllocationJob, this));
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void V4l2Decoder::flushDecoderJob()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
if (m_decoder)
|
|
Packit |
1244b8 |
m_decoder->flush();
|
|
Packit |
1244b8 |
m_output->flush();
|
|
Packit |
1244b8 |
m_state = kStopped;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onStreamOff(uint32_t type)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
|
|
Packit |
1244b8 |
|| type == (unsigned int)V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
|
|
Packit |
1244b8 |
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
Packit |
1244b8 |
if (m_inputOn) {
|
|
Packit |
1244b8 |
post(bind(&V4l2Decoder::flushDecoderJob, this));
|
|
Packit |
1244b8 |
m_thread.stop();
|
|
Packit |
1244b8 |
m_in.clearPipe();
|
|
Packit |
1244b8 |
m_inputOn = false;
|
|
Packit |
1244b8 |
m_state = kUnStarted;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
m_outputOn = false;
|
|
Packit |
1244b8 |
m_output->streamOff();
|
|
Packit |
1244b8 |
m_out.clearPipe();
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::requestInputBuffers(uint32_t count)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(m_thread.isCurrent());
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
uint32_t size = m_inputFormat.fmt.pix_mp.plane_fmt[0].sizeimage;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
m_inputFrames.resize(count);
|
|
Packit |
1244b8 |
if (count) {
|
|
Packit |
1244b8 |
//this means we really need allocate space
|
|
Packit |
1244b8 |
if (!size)
|
|
Packit |
1244b8 |
m_inputFormat.fmt.pix_mp.plane_fmt[0].sizeimage = kDefaultInputSize;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
m_inputSpace.resize(count * size);
|
|
Packit |
1244b8 |
m_inputFrames.resize(count);
|
|
Packit |
1244b8 |
for (uint32_t i = 0; i < count; i++) {
|
|
Packit |
1244b8 |
VideoDecodeBuffer& frame = m_inputFrames[i];
|
|
Packit |
1244b8 |
memset(&frame, 0, sizeof(frame));
|
|
Packit |
1244b8 |
frame.data = &m_inputSpace[i * size];
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onRequestBuffers(const v4l2_requestbuffers* req)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(req);
|
|
Packit |
1244b8 |
uint32_t type = req->type;
|
|
Packit |
1244b8 |
uint32_t count = req->count;
|
|
Packit |
1244b8 |
CHECK(type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
|
|
Packit |
1244b8 |
|| type == (unsigned int)V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
|
|
Packit |
1244b8 |
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
Packit |
1244b8 |
CHECK(req->memory == V4L2_MEMORY_MMAP);
|
|
Packit |
1244b8 |
return sendTask(bind(&V4l2Decoder::requestInputBuffers, this, count));
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
CHECK(req->memory == V4L2_MEMORY_MMAP);
|
|
Packit |
1244b8 |
return sendTask(bind(&Output::requestBuffers, m_output, count));
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onSetFormat(v4l2_format* format)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(format);
|
|
Packit |
1244b8 |
CHECK(!m_inputOn && !m_outputOn);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
|
Packit |
1244b8 |
uint32_t size;
|
|
Packit |
1244b8 |
memcpy(&size, format->fmt.raw_data, sizeof(uint32_t));
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
CHECK(size <= (sizeof(format->fmt.raw_data) - sizeof(uint32_t)));
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
uint8_t* ptr = format->fmt.raw_data;
|
|
Packit |
1244b8 |
ptr += sizeof(uint32_t);
|
|
Packit |
1244b8 |
m_codecData.assign(ptr, ptr + size);
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (format->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
Packit |
1244b8 |
CHECK(format->fmt.pix_mp.num_planes == 1);
|
|
Packit |
1244b8 |
CHECK(format->fmt.pix_mp.plane_fmt[0].sizeimage);
|
|
Packit |
1244b8 |
memcpy(&m_inputFormat, format, sizeof(*format));
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
ERROR("unknow type: %d of setting format VIDIOC_S_FMT", format->type);
|
|
Packit |
1244b8 |
return -1;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onQueryBuffer(v4l2_buffer* buf)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(buf);
|
|
Packit |
1244b8 |
CHECK(buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
|
|
Packit |
1244b8 |
CHECK(buf->memory == V4L2_MEMORY_MMAP);
|
|
Packit |
1244b8 |
CHECK(m_inputFormat.fmt.pix_mp.num_planes == 1);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
uint32_t idx = buf->index;
|
|
Packit |
1244b8 |
uint32_t size = m_inputFormat.fmt.pix_mp.plane_fmt[0].sizeimage;
|
|
Packit |
1244b8 |
CHECK(size);
|
|
Packit |
1244b8 |
buf->m.planes[0].length = size;
|
|
Packit |
1244b8 |
buf->m.planes[0].m.mem_offset = size * idx;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onSubscribeEvent(v4l2_event_subscription* sub)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(sub->type == V4L2_EVENT_RESOLUTION_CHANGE);
|
|
Packit |
1244b8 |
/// resolution change event is must, we always do so
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onDequeEvent(v4l2_event* ev)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(ev);
|
|
Packit |
1244b8 |
if (hasCodecEvent()) {
|
|
Packit |
1244b8 |
ev->type = V4L2_EVENT_RESOLUTION_CHANGE;
|
|
Packit |
1244b8 |
clearCodecEvent();
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
return -1;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onGetFormat(v4l2_format* format)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(format && format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
|
|
Packit |
1244b8 |
CHECK(m_inputOn);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
SEND(bind(&V4l2Decoder::getFormatTask, this, format));
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
//save it.
|
|
Packit |
1244b8 |
m_outputFormat = *format;
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onGetCtrl(v4l2_control* ctrl)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(ctrl);
|
|
Packit |
1244b8 |
CHECK(ctrl->id == V4L2_CID_MIN_BUFFERS_FOR_CAPTURE);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
SEND(bind(&V4l2Decoder::getCtrlTask, this, ctrl));
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onEnumFormat(v4l2_fmtdesc* fmtdesc)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
uint32_t type = fmtdesc->type;
|
|
Packit |
1244b8 |
uint32_t index = fmtdesc->index;
|
|
Packit |
1244b8 |
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
|
Packit |
1244b8 |
CHECK(!index);
|
|
Packit |
1244b8 |
fmtdesc->pixelformat = V4L2_PIX_FMT_NV12M;
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
Packit |
1244b8 |
//TODO: query from libyami when capablity api is ready.
|
|
Packit |
1244b8 |
const static uint32_t supported[] = {
|
|
Packit |
1244b8 |
V4L2_PIX_FMT_H264,
|
|
Packit |
1244b8 |
V4L2_PIX_FMT_VC1,
|
|
Packit |
1244b8 |
V4L2_PIX_FMT_MPEG2,
|
|
Packit |
1244b8 |
V4L2_PIX_FMT_JPEG,
|
|
Packit |
1244b8 |
V4L2_PIX_FMT_VP8,
|
|
Packit |
1244b8 |
V4L2_PIX_FMT_VP9,
|
|
Packit |
1244b8 |
};
|
|
Packit |
1244b8 |
CHECK(index < N_ELEMENTS(supported));
|
|
Packit |
1244b8 |
fmtdesc->pixelformat = supported[index];
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
return -1;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onGetCrop(v4l2_crop* crop)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
|
|
Packit |
1244b8 |
ASSERT(0);
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
//return sendTask(m_decoderThread, std::bind(getCrop,crop)));
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::onCreateBuffers(v4l2_create_buffers* req)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
return m_output->createBuffers(req);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void V4l2Decoder::startDecoderJob()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
PCHECK(m_state == kUnStarted);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (m_decoder) {
|
|
Packit |
1244b8 |
m_state = kGetInput;
|
|
Packit |
1244b8 |
getInputJob();
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
const char* mime = mimeFromV4l2PixelFormat(m_inputFormat.fmt.pix_mp.pixelformat);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
m_decoder.reset(
|
|
Packit |
1244b8 |
createVideoDecoder(mime), releaseVideoDecoder);
|
|
Packit |
1244b8 |
if (!m_decoder) {
|
|
Packit |
1244b8 |
ERROR("create display failed");
|
|
Packit |
1244b8 |
m_display.reset();
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
m_output->setDecodeAllocator(m_decoder);
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
YamiStatus status;
|
|
Packit |
1244b8 |
VideoConfigBuffer config;
|
|
Packit |
1244b8 |
memset(&config, 0, sizeof(config));
|
|
Packit |
1244b8 |
config.width = m_inputFormat.fmt.pix_mp.width;
|
|
Packit |
1244b8 |
config.height = m_inputFormat.fmt.pix_mp.height;
|
|
Packit |
1244b8 |
config.data = &m_codecData[0];
|
|
Packit |
1244b8 |
config.size = m_codecData.size();
|
|
Packit |
1244b8 |
if (m_isThumbnailMode) {
|
|
Packit |
1244b8 |
DEBUG("enable lowlatency mode");
|
|
Packit |
1244b8 |
config.enableLowLatency = true;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
status = m_decoder->start(&config);
|
|
Packit |
1244b8 |
if (status != YAMI_SUCCESS) {
|
|
Packit |
1244b8 |
ERROR("start decoder failed");
|
|
Packit |
1244b8 |
return;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
const VideoFormatInfo* outFormat = m_decoder->getFormatInfo();
|
|
Packit |
1244b8 |
if (outFormat && outFormat->width && outFormat->height) {
|
|
Packit |
1244b8 |
//we got format now, we are waiting for surface allocation.
|
|
Packit |
1244b8 |
m_state = kWaitAllocation;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
else {
|
|
Packit |
1244b8 |
m_state = kGetInput;
|
|
Packit |
1244b8 |
getInputJob();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void V4l2Decoder::post(Job job)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
m_thread.post(job);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
static void taskWrapper(int32_t& ret, Task& task)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
ret = task();
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::sendTask(Task task)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
//if send fail, we will return EINVAL;
|
|
Packit |
1244b8 |
int32_t ret = EINVAL;
|
|
Packit |
1244b8 |
m_thread.send(bind(taskWrapper, ref(ret), ref(task)));
|
|
Packit |
1244b8 |
return ret;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::getFormatTask(v4l2_format* format)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(m_thread.isCurrent());
|
|
Packit |
1244b8 |
CHECK(format);
|
|
Packit |
1244b8 |
CHECK(bool(m_decoder));
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
const VideoFormatInfo* outFormat = m_decoder->getFormatInfo();
|
|
Packit |
1244b8 |
if (!outFormat)
|
|
Packit |
1244b8 |
return EINVAL;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
memset(format, 0, sizeof(*format));
|
|
Packit |
1244b8 |
format->fmt.pix_mp.width = outFormat->width;
|
|
Packit |
1244b8 |
format->fmt.pix_mp.height = outFormat->height;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
//TODO: add support for P010
|
|
Packit |
1244b8 |
format->fmt.pix_mp.num_planes = 2; //for NV12
|
|
Packit |
1244b8 |
format->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
//we can't fill format->fmt.pix_mp.plane_fmt[0].bytesperline
|
|
Packit |
1244b8 |
//yet, since we did not creat surface.
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::getCtrlTask(v4l2_control* ctrl)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
CHECK(m_thread.isCurrent());
|
|
Packit |
1244b8 |
CHECK(ctrl);
|
|
Packit |
1244b8 |
CHECK(bool(m_decoder));
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
const VideoFormatInfo* outFormat = m_decoder->getFormatInfo();
|
|
Packit |
1244b8 |
if (!outFormat)
|
|
Packit |
1244b8 |
return EINVAL;
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
if (m_isThumbnailMode) {
|
|
Packit |
1244b8 |
ctrl->value = 1;
|
|
Packit |
1244b8 |
} else {
|
|
Packit |
1244b8 |
//TODO: query this from outFormat;
|
|
Packit |
1244b8 |
ctrl->value = outFormat->surfaceNumber;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
#define MCHECK(cond) \
|
|
Packit |
1244b8 |
do { \
|
|
Packit |
1244b8 |
if (!(cond)) { \
|
|
Packit |
1244b8 |
ERROR("%s is false", #cond); \
|
|
Packit |
1244b8 |
return NULL; \
|
|
Packit |
1244b8 |
} \
|
|
Packit |
1244b8 |
} while (0)
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void* V4l2Decoder::mmap(void* addr, size_t length,
|
|
Packit |
1244b8 |
int prot, int flags, unsigned int offset)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
MCHECK(prot == (PROT_READ | PROT_WRITE));
|
|
Packit |
1244b8 |
MCHECK(flags == MAP_SHARED);
|
|
Packit |
1244b8 |
uint32_t size = m_inputFormat.fmt.pix_mp.plane_fmt[0].sizeimage;
|
|
Packit |
1244b8 |
MCHECK(size);
|
|
Packit |
1244b8 |
MCHECK(length == size);
|
|
Packit |
1244b8 |
MCHECK(!(offset % size));
|
|
Packit |
1244b8 |
MCHECK(offset / size < m_inputFrames.size());
|
|
Packit |
1244b8 |
MCHECK(offset + size <= m_inputSpace.size());
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
return &m_inputSpace[offset];
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
#undef MCHECK
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::setFrameMemoryType(VideoDataMemoryType memory_type)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
if (memory_type == VIDEO_DATA_MEMORY_TYPE_EXTERNAL_DMA_BUF)
|
|
Packit |
1244b8 |
m_output.reset(new ExternalDmaBufOutput(this));
|
|
Packit |
1244b8 |
#ifdef __ENABLE_EGL__
|
|
Packit |
1244b8 |
if (memory_type == VIDEO_DATA_MEMORY_TYPE_DRM_NAME
|
|
Packit |
1244b8 |
|| memory_type == VIDEO_DATA_MEMORY_TYPE_DMA_BUF)
|
|
Packit |
1244b8 |
m_output.reset(new EglOutput(this, memory_type));
|
|
Packit |
1244b8 |
#endif
|
|
Packit |
1244b8 |
if (!m_output) {
|
|
Packit |
1244b8 |
ERROR("unspported memory type %d", memory_type);
|
|
Packit |
1244b8 |
return -1;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
return 0;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
void V4l2Decoder::flush()
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
|
|
Packit |
1244b8 |
#ifdef __ENABLE_EGL__
|
|
Packit |
1244b8 |
int32_t V4l2Decoder::useEglImage(EGLDisplay eglDisplay, EGLContext eglContext, uint32_t bufferIndex, void* eglImage)
|
|
Packit |
1244b8 |
{
|
|
Packit |
1244b8 |
SharedPtr<EglOutput> output = DynamicPointerCast<EglOutput>(m_output);
|
|
Packit |
1244b8 |
if (!output) {
|
|
Packit |
1244b8 |
ERROR("can't cast m_output to EglOutput");
|
|
Packit |
1244b8 |
return -1;
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
return output->useEglImage(eglDisplay, eglContext, bufferIndex, eglImage);
|
|
Packit |
1244b8 |
}
|
|
Packit |
1244b8 |
#endif
|