Skip to content

Commit

Permalink
example: add alpha blend app
Browse files Browse the repository at this point in the history
an alpha blending application to render random color blocks on a video.
  • Loading branch information
xuguangxin committed Jan 10, 2016
1 parent 9db518b commit 8aa0c71
Show file tree
Hide file tree
Showing 4 changed files with 410 additions and 2 deletions.
9 changes: 9 additions & 0 deletions examples/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ bin_PROGRAMS =

if ENABLE_X11
bin_PROGRAMS += simpleplayer

if BUILD_OCL_BLENDER
bin_PROGRAMS += blend
endif

endif

if ENABLE_DMABUF
Expand Down Expand Up @@ -107,6 +112,10 @@ if ENABLE_X11
simpleplayer_LDADD = $(YAMI_DECODE_LIBS)
simpleplayer_LDFLAGS = $(YAMI_DECODE_LDFLAGS)
simpleplayer_SOURCES = simpleplayer.cpp $(DECODE_INPUT_SOURCES)

blend_LDADD = $(VPP_INPUT_LIBS) -lpthread
blend_LDFLAGS = $(VPP_INPUT_LDFLAGS)
blend_SOURCES = blend.cpp $(VPP_INPUT_SOURCES)
endif

if ENABLE_DMABUF
Expand Down
317 changes: 317 additions & 0 deletions examples/blend.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
/*
* blend.cpp - blend to demo API usage, no tricks
*
* Copyright (C) 2013-2014 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "bumpbox.h"
#include "vppinputdecode.h"
#include "common/log.h"
#include "common/utils.h"
#include "common/common_def.h"
#include "vaapi/vaapiutils.h"
#include "VideoDecoderHost.h"
#include "VideoPostProcessHost.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <vector>

#include <X11/Xlib.h>
#include <va/va.h>
#include <va/va_x11.h>

using namespace YamiMediaCodec;
using namespace std;

class VideoFrameDeleter
{
public:
VideoFrameDeleter(VADisplay display):m_display(display)
{
}
void operator()(VideoFrame* frame)
{
VASurfaceID id = (VASurfaceID)frame->surface;
vaDestroySurfaces(m_display, &id, 1);
}
private:
VADisplay m_display;

};

#define ROOF(a, b) (a & (b - 1)

class Blend
{
public:
bool init(int argc, char** argv)
{
if (argc != 2) {
printf("usage: blend xxx.264\n");
return false;
}
m_input.reset(new VppInputDecode);
if (!m_input->init(argv[1])) {
fprintf(stderr, "failed to open %s", argv[1]);
return false;
}

if (!initDisplay()) {
return false;
}
//set native display
if (!m_input->config(*m_nativeDisplay))
return false;
if (!createVpp())
return false;
setRandomSeed();
int width = m_input->getWidth();
int height = m_input->getHeight();
if (!createBlendSurfaces(width, height))
return false;
if (!createDestSurface(width, height))
return false;
resizeWindow(800, 600);
return true;
}
bool run()
{
SharedPtr<VideoFrame> frame;
VAStatus status;
while (m_input->read(frame)) {
//copy the decoded surface
memset(&m_dest->crop, 0, sizeof(VideoRect));
m_scaler->process(frame, m_dest);

//blend it
for (int i = 0; i < m_blendSurfaces.size(); i++) {
m_bumpBoxes[i]->getPos(m_dest->crop.x, m_dest->crop.y, m_dest->crop.width, m_dest->crop.height);
//printf("(%d, %d, %d, %d)\r\n", m_dest->crop.x, m_dest->crop.y, m_dest->crop.width, m_dest->crop.height);

SharedPtr<VideoFrame>& src = m_blendSurfaces[i];
m_blender->process(src, m_dest);
}

//display it on screen
memcpy(&m_dest->crop, &frame->crop, sizeof(VideoRect));
status = vaPutSurface(m_vaDisplay, (VASurfaceID)m_dest->surface,
m_window, m_dest->crop.x, m_dest->crop.y, m_dest->crop.width, m_dest->crop.height, 0, 0, m_width, m_height,
NULL, 0, 0);
if (status != VA_STATUS_SUCCESS) {
ERROR("vaPutSurface return %d", status);
break;
}

}
return true;
}
Blend():m_window(0), m_width(0), m_height(0) {}
~Blend()
{
m_input.reset();
if (m_nativeDisplay) {
vaTerminate(m_vaDisplay);
}
if (m_window) {
XDestroyWindow(m_display.get(), m_window);
}
}
private:
void setRandomSeed()
{
time_t t = time(NULL);
unsigned int seed = (unsigned int)t;
printf("set seed to %d\r\n", seed);
srand(seed);
}
bool initDisplay()
{
Display* display = XOpenDisplay(NULL);
if (!display) {
fprintf(stderr, "Failed to XOpenDisplay \n");
return false;
}
m_display.reset(display, XCloseDisplay);
m_vaDisplay = vaGetDisplay(m_display.get());
int major, minor;
VAStatus status;
status = vaInitialize(m_vaDisplay, &major, &minor);
if (status != VA_STATUS_SUCCESS) {
fprintf(stderr, "init va failed status = %d", status);
return false;
}
m_nativeDisplay.reset(new NativeDisplay);
m_nativeDisplay->type = NATIVE_DISPLAY_VA;
m_nativeDisplay->handle = (intptr_t)m_vaDisplay;
return true;
}
SharedPtr<VideoFrame> createSurface(uint32_t rtFormat, int pixelFormat, uint32_t width, uint32_t height)
{
SharedPtr<VideoFrame> frame;
VAStatus status;
VASurfaceID id;
VASurfaceAttrib attrib;
attrib.type = VASurfaceAttribPixelFormat;
attrib.flags = VA_SURFACE_ATTRIB_SETTABLE;
attrib.value.type = VAGenericValueTypeInteger;
attrib.value.value.i = pixelFormat;

status = vaCreateSurfaces(m_vaDisplay, rtFormat, width, height, &id, 1, &attrib, 1);
if (!checkVaapiStatus(status, "vaCreateSurfaces"))
return frame;
frame.reset(new VideoFrame, VideoFrameDeleter(m_vaDisplay));
frame->surface = (intptr_t)id;
frame->crop.x = frame->crop.y = 0;
frame->crop.width = width;
frame->crop.height = height;
return frame;
}

bool drawSurfaceRGBA(SharedPtr<VideoFrame>& frame)
{
VASurfaceID surface = (VASurfaceID)frame->surface;
VAImage image;

VAStatus status = vaDeriveImage(m_vaDisplay,surface,&image);
if (!checkVaapiStatus(status, "vaDeriveImage"))
return false;
assert(image.num_planes == 1);
char* buf;
status = vaMapBuffer(m_vaDisplay, image.buf, (void**)&buf);
if (!checkVaapiStatus(status, "vaMapBuffer")) {
vaDestroyImage(m_vaDisplay, image.image_id);
return false;
}

uint8_t r = rand() % 256;
uint8_t g = rand() % 256;
uint8_t b = rand() % 256;
uint8_t a = rand() % 256;

uint32_t pixel = (r << 24) | (g << 16) | (b << 8) | a;
char* ptr = buf + image.offsets[0];
for (int i = 0; i < image.height; i++) {
uint32_t* dest = (uint32_t*)(ptr + image.pitches[0] * i);
for (int j = 0; j < image.width; j++) {
*dest = pixel;
dest++;
}
}
checkVaapiStatus(vaUnmapBuffer(m_vaDisplay, image.buf), "vaUnmapBuffer");
checkVaapiStatus(vaDestroyImage(m_vaDisplay, image.image_id), "vaDestroyImage");
return true;
}

bool createBlendSurfaces(uint32_t targetWidth, uint32_t targetHeight)
{
uint32_t maxWidth = targetWidth / 2;
uint32_t maxHeight = targetHeight / 2;
for (int i = 0; i < 3; i++) {
int w = ALIGN_POW2(rand() % maxWidth + 1, 2);
int h = ALIGN_POW2(rand() % maxHeight + 1, 2);

SharedPtr<VideoFrame> frame = createSurface(VA_RT_FORMAT_RGB32, VA_FOURCC_RGBA, w, h);
if (!frame)
return false;
drawSurfaceRGBA(frame);
m_blendSurfaces.push_back(frame);
SharedPtr<BumpBox> box(new BumpBox(targetWidth, targetHeight, w, h));
m_bumpBoxes.push_back(box);
}
return true;

}

bool createDestSurface(uint32_t targetWidth, uint32_t targetHeight)
{
m_dest = createSurface(VA_RT_FORMAT_YUV420, VA_FOURCC_NV12, targetWidth, targetHeight );
return m_dest;
}

bool createVpp()
{
NativeDisplay nativeDisplay;
nativeDisplay.type = NATIVE_DISPLAY_VA;
nativeDisplay.handle = (intptr_t)m_vaDisplay;
m_scaler.reset(createVideoPostProcess(YAMI_VPP_SCALER), releaseVideoPostProcess);
m_blender.reset(createVideoPostProcess(YAMI_VPP_OCL_BLENDER), releaseVideoPostProcess);
if (!m_scaler || !m_blender)
return false;
return m_scaler->setNativeDisplay(nativeDisplay) == YAMI_SUCCESS
&& m_blender->setNativeDisplay(nativeDisplay) == YAMI_SUCCESS;
}

void resizeWindow(int width, int height)
{
Display* display = m_display.get();
if (m_window) {
//todo, resize window;
} else {
DefaultScreen(display);

XSetWindowAttributes x11WindowAttrib;
x11WindowAttrib.event_mask = KeyPressMask;
m_window = XCreateWindow(display, DefaultRootWindow(display),
0, 0, width, height, 0, CopyFromParent, InputOutput,
CopyFromParent, CWEventMask, &x11WindowAttrib);
XMapWindow(display, m_window);
}
XSync(display, false);
{
DEBUG("m_window=%lu", m_window);
XWindowAttributes wattr;
XGetWindowAttributes(display, m_window, &wattr);
}
m_width = width;
m_height = height;
}
SharedPtr<Display> m_display;
SharedPtr<NativeDisplay> m_nativeDisplay;
VADisplay m_vaDisplay;
Window m_window;
SharedPtr<VppInputDecode> m_input;
SharedPtr<IVideoPostProcess> m_scaler;
SharedPtr<IVideoPostProcess> m_blender;
int m_width, m_height;
vector<SharedPtr<VideoFrame> > m_blendSurfaces;
vector<SharedPtr<BumpBox> > m_bumpBoxes;
SharedPtr<VideoFrame> m_dest;
};

int main(int argc, char** argv)
{

Blend player;
if (!player.init(argc, argv)) {
ERROR("init player failed with %s", argv[1]);
return -1;
}
if (!player.run()){
ERROR("run blend failed");
return -1;
}
printf("play file done\n");
return 0;

}

Loading

0 comments on commit 8aa0c71

Please sign in to comment.