diff --git a/Makefile b/Makefile index 6df3701..67d0bee 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,22 @@ -CPPFLAGS+= -g -Wall -std=gnu99 -I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux -LDFLAGS+=-L/opt/vc/lib/ -lGLESv2 -lEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm +CFLAGS += -g -Wall -std=gnu99 -I$(SYSROOT)/opt/vc/include/ -I$(SYSROOT)/opt/vc/include/interface/vcos/pthreads -I$(SYSROOT)/opt/vc/include/interface/vmcs_host/linux +LDFLAGS += -L$(SYSROOT)/opt/vc/lib/ -lGLESv2 -lEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm all: osd %.o: %.c - gcc -c -o $@ $< $(CPPFLAGS) + $(CC) -c -o $@ $< $(CFLAGS) osd: main.o osdrender.o osdmavlink.o graphengine.o UAVObj.o m2dlib.o math3d.o osdconfig.o osdvar.o fonts.o font_outlined8x14.o font_outlined8x8.o oglinit.o - gcc -o $@ $^ $(LDFLAGS) + $(CC) -o $@ $^ $(LDFLAGS) + +build_rpi: clean + docker build docker -t wifibroadcast_osd:rpi_raspbian + docker run -i -t --rm -v $(PWD):/build -v $(PWD):/rpxc/sysroot/build wifibroadcast_osd:rpi_raspbian sh -c 'CFLAGS=--sysroot=/rpxc/sysroot LDFLAGS="--sysroot=/rpxc/sysroot" CXX=arm-linux-gnueabihf-g++ CC=arm-linux-gnueabihf-gcc make' + docker run -i -t --rm -v $(PWD):/build -v $(PWD):/rpxc/sysroot/build wifibroadcast_osd:rpi_raspbian sh -c 'cd /rpxc/sysroot/opt/vc/src/hello_pi/libs/ilclient; SDKSTAGE=/rpxc/sysroot CFLAGS=--sysroot=/rpxc/sysroot LDFLAGS="--sysroot=/rpxc/sysroot" CXX=arm-linux-gnueabihf-g++ CC=arm-linux-gnueabihf-gcc make; cd /build/fpv_video; SDKSTAGE=/rpxc/sysroot CFLAGS=--sysroot=/rpxc/sysroot LDFLAGS="--sysroot=/rpxc/sysroot" CXX=arm-linux-gnueabihf-g++ CC=arm-linux-gnueabihf-gcc make' + mkdir -p dist + tar czf dist/wifibroadcast_osd.tar.gz osd -C fpv_video fpv_video fpv_video.sh clean: rm -f osd *.o *~ + make -C fpv_video clean diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..c08a881 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,2 @@ +FROM sdthirlwall/raspberry-pi-cross-compiler +RUN install-raspbian libraspberrypi0 libraspberrypi-dev libraspberrypi-doc libraspberrypi-bin diff --git a/fpv_video/Makefile b/fpv_video/Makefile new file mode 100644 index 0000000..2cd59fc --- /dev/null +++ b/fpv_video/Makefile @@ -0,0 +1,6 @@ +OBJS=fpv_video.o +BIN=fpv_video +LDFLAGS+=-lilclient + +include Makefile.include + diff --git a/fpv_video/Makefile.include b/fpv_video/Makefile.include new file mode 100644 index 0000000..8f5adae --- /dev/null +++ b/fpv_video/Makefile.include @@ -0,0 +1,27 @@ +CFLAGS+=-DSTANDALONE -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -DTARGET_POSIX -D_LINUX -fPIC -DPIC -D_REENTRANT -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -U_FORTIFY_SOURCE -Wall -g -DHAVE_LIBOPENMAX=2 -DOMX -DOMX_SKIP64BIT -ftree-vectorize -pipe -DUSE_EXTERNAL_OMX -DHAVE_LIBBCM_HOST -DUSE_EXTERNAL_LIBBCM_HOST -DUSE_VCHIQ_ARM -Wno-psabi + +LDFLAGS+=-L$(SDKSTAGE)/opt/vc/lib/ -lbrcmGLESv2 -lbrcmEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm -L$(SDKSTAGE)/opt/vc/src/hello_pi/libs/ilclient -L$(SDKSTAGE)/opt/vc/src/hello_pi/libs/vgfont + +INCLUDES+=-I$(SDKSTAGE)/opt/vc/include/ -I$(SDKSTAGE)/opt/vc/include/interface/vcos/pthreads -I$(SDKSTAGE)/opt/vc/include/interface/vmcs_host/linux -I./ -I$(SDKSTAGE)/opt/vc/src/hello_pi/libs/ilclient -I$(SDKSTAGE)/opt/vc/src/hello_pi/libs/vgfont + +all: $(BIN) $(LIB) + +%.o: %.c + @rm -f $@ + $(CC) $(CFLAGS) $(INCLUDES) -g -c $< -o $@ -Wno-deprecated-declarations + +%.o: %.cpp + @rm -f $@ + $(CXX) $(CFLAGS) $(INCLUDES) -g -c $< -o $@ -Wno-deprecated-declarations + +$(BIN): $(OBJS) + $(CC) -o $@ -Wl,--whole-archive $(OBJS) $(LDFLAGS) -Wl,--no-whole-archive -rdynamic + +%.a: $(OBJS) + $(AR) r $@ $^ + +clean: + for i in $(OBJS); do (if test -e "$$i"; then ( rm -f $$i ); fi ); done + @rm -f $(BIN) $(LIB) + + diff --git a/fpv_video/fpv_video.c b/fpv_video/fpv_video.c new file mode 100644 index 0000000..ee170d0 --- /dev/null +++ b/fpv_video/fpv_video.c @@ -0,0 +1,238 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// Video deocode demo using OpenMAX IL though the ilcient helper library + +#include +#include +#include + +#include "bcm_host.h" +#include "ilclient.h" + +#define OMX_INIT_STRUCTURE(a) \ + memset(&(a), 0, sizeof(a)); \ + (a).nSize = sizeof(a); \ + (a).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \ + (a).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \ + (a).nVersion.s.nRevision = OMX_VERSION_REVISION; \ + (a).nVersion.s.nStep = OMX_VERSION_STEP + +static int video_decode_test() +{ + OMX_VIDEO_PARAM_PORTFORMATTYPE format; + OMX_TIME_CONFIG_CLOCKSTATETYPE cstate; + + COMPONENT_T *video_decode = NULL, *video_scheduler = NULL, *video_render = NULL, *clock = NULL; + COMPONENT_T *list[5]; + TUNNEL_T tunnel[4]; + ILCLIENT_T *client; + int status = 0; + unsigned int data_len = 0; + + memset(list, 0, sizeof(list)); + memset(tunnel, 0, sizeof(tunnel)); + + if((client = ilclient_init()) == NULL) + { + return -3; + } + + if(OMX_Init() != OMX_ErrorNone) + { + ilclient_destroy(client); + return -4; + } + + // create video_decode + if(ilclient_create_component(client, &video_decode, "video_decode", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS) != 0) + status = -14; + list[0] = video_decode; + + // create video_render + if(status == 0 && ilclient_create_component(client, &video_render, "video_render", ILCLIENT_DISABLE_ALL_PORTS) != 0) + status = -14; + list[1] = video_render; + + // create clock + if(status == 0 && ilclient_create_component(client, &clock, "clock", ILCLIENT_DISABLE_ALL_PORTS) != 0) + status = -14; + list[2] = clock; + + memset(&cstate, 0, sizeof(cstate)); + cstate.nSize = sizeof(cstate); + cstate.nVersion.nVersion = OMX_VERSION; + cstate.eState = OMX_TIME_ClockStateWaitingForStartTime; + cstate.nWaitMask = 1; + if(clock != NULL && OMX_SetParameter(ILC_GET_HANDLE(clock), OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone) + status = -13; + + // create video_scheduler + if(status == 0 && ilclient_create_component(client, &video_scheduler, "video_scheduler", ILCLIENT_DISABLE_ALL_PORTS) != 0) + status = -14; + list[3] = video_scheduler; + + set_tunnel(tunnel, video_decode, 131, video_scheduler, 10); + set_tunnel(tunnel+1, video_scheduler, 11, video_render, 90); + set_tunnel(tunnel+2, clock, 80, video_scheduler, 12); + + // setup clock tunnel first + if(status == 0 && ilclient_setup_tunnel(tunnel+2, 0, 0) != 0) + status = -15; + else + ilclient_change_component_state(clock, OMX_StateExecuting); + + if(status == 0) + ilclient_change_component_state(video_decode, OMX_StateIdle); + + memset(&format, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE)); + format.nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE); + format.nVersion.nVersion = OMX_VERSION; + format.nPortIndex = 130; + format.eCompressionFormat = OMX_VIDEO_CodingAVC; + format.xFramerate = 30 << 16; + + if(status == 0 && + OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamVideoPortFormat, &format) == OMX_ErrorNone && + ilclient_enable_port_buffers(video_decode, 130, NULL, NULL, NULL) == 0) + { + OMX_BUFFERHEADERTYPE *buf; + int port_settings_changed = 0; + int first_packet = 1; + + ilclient_change_component_state(video_decode, OMX_StateExecuting); + + { + OMX_CONFIG_DISPLAYREGIONTYPE display; + OMX_ERRORTYPE omx_err; + + OMX_INIT_STRUCTURE(display); + display.nPortIndex = 90; + display.set = (OMX_DISPLAYSETTYPE)OMX_DISPLAY_SET_NOASPECT; + display.noaspect = OMX_TRUE; + + omx_err = OMX_SetParameter(ILC_GET_HANDLE(video_render), OMX_IndexConfigDisplayRegion, &display); + + if (omx_err != OMX_ErrorNone) + { + printf("Unable to set aspect: 0x%x\n", omx_err); + } + } + + while((buf = ilclient_get_input_buffer(video_decode, 130, 1)) != NULL) + { + // feed data and wait until we get port settings changed + unsigned char *dest = buf->pBuffer; + + data_len = read(STDIN_FILENO, dest, buf->nAllocLen-data_len); + + + if(port_settings_changed == 0 && + ((data_len > 0 && ilclient_remove_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) || + (data_len == 0 && ilclient_wait_for_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1, + ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0))) + { + port_settings_changed = 1; + + if(ilclient_setup_tunnel(tunnel, 0, 0) != 0) + { + status = -7; + break; + } + + ilclient_change_component_state(video_scheduler, OMX_StateExecuting); + + // now setup tunnel to video_render + if(ilclient_setup_tunnel(tunnel+1, 0, 1000) != 0) + { + status = -12; + break; + } + + ilclient_change_component_state(video_render, OMX_StateExecuting); + } + if(!data_len) + break; + + buf->nFilledLen = data_len; + data_len = 0; + + buf->nOffset = 0; + if(first_packet) + { + buf->nFlags = OMX_BUFFERFLAG_STARTTIME; + first_packet = 0; + } + else + buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN; + + if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone) + { + status = -6; + break; + } + } + + buf->nFilledLen = 0; + buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS; + + if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone) + status = -20; + + // wait for EOS from render + ilclient_wait_for_event(video_render, OMX_EventBufferFlag, 90, 0, OMX_BUFFERFLAG_EOS, 0, + ILCLIENT_BUFFER_FLAG_EOS, -1); + //ILCLIENT_BUFFER_FLAG_EOS, 10000); + + // need to flush the renderer to allow video_decode to disable its input port + ilclient_flush_tunnels(tunnel, 0); + + } + + + ilclient_disable_tunnel(tunnel); + ilclient_disable_tunnel(tunnel+1); + ilclient_disable_tunnel(tunnel+2); + ilclient_disable_port_buffers(video_decode, 130, NULL, NULL, NULL); + ilclient_teardown_tunnels(tunnel); + + ilclient_state_transition(list, OMX_StateIdle); + ilclient_state_transition(list, OMX_StateLoaded); + + ilclient_cleanup_components(list); + + OMX_Deinit(); + + ilclient_destroy(client); + return status; +} + +int main (int argc, char **argv) +{ + bcm_host_init(); + return video_decode_test(); +} diff --git a/fpv_video/fpv_video.sh b/fpv_video/fpv_video.sh new file mode 100755 index 0000000..7527732 --- /dev/null +++ b/fpv_video/fpv_video.sh @@ -0,0 +1,2 @@ +#!/bin/bash +gst-launch-1.0 udpsrc port=5600 caps='application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264' ! rtph264depay ! 'video/x-h264,stream-format=byte-stream' ! fdsink | ./fpv_video diff --git a/osdrender.h b/osdrender.h index 22c7fa9..1bea3e8 100644 --- a/osdrender.h +++ b/osdrender.h @@ -19,8 +19,6 @@ #include "bcm_host.h" #include "VG/openvg.h" #include "VG/vgu.h" -#include "fontinfo.h" -#include "shapes.h" #include #include #include "graphengine.h"