diff --git a/src/hello_video/Makefile b/src/hello_video/Makefile new file mode 100644 index 0000000..11ad4e4 --- /dev/null +++ b/src/hello_video/Makefile @@ -0,0 +1,6 @@ +OBJS=video.o +BIN=hello_video.bin +LDFLAGS+=-lilclient + +include Makefile.include + diff --git a/src/hello_video/Makefile.include b/src/hello_video/Makefile.include new file mode 100644 index 0000000..9267e86 --- /dev/null +++ b/src/hello_video/Makefile.include @@ -0,0 +1,28 @@ + +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/ -lGLESv2 -lEGL -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 $$i ); fi ); done + @rm -f $(BIN) $(LIB) + + diff --git a/src/hello_video/README b/src/hello_video/README new file mode 100644 index 0000000..c4922d9 --- /dev/null +++ b/src/hello_video/README @@ -0,0 +1 @@ +The video clip test.h264 is (c) copyright 2008, Blender Foundation / www.bigbuckbunny.org diff --git a/src/hello_video/video.c b/src/hello_video/video.c new file mode 100644 index 0000000..04a7476 --- /dev/null +++ b/src/hello_video/video.c @@ -0,0 +1,262 @@ +/* +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" + +OMX_TICKS ToOMXTime(int64_t pts) +{ + OMX_TICKS ticks; + ticks.nLowPart = pts; + ticks.nHighPart = pts >> 32; + return ticks; +} + +static inline uint64_t FromOMXTime(OMX_TICKS ticks) +{ + uint64_t pts = ticks.nLowPart | ((uint64_t)ticks.nHighPart << 32); + return pts; +} + +static int video_decode_test(char *filename) +{ + 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; + FILE *in; + int status = 0; + unsigned int data_len = 0; + + memset(list, 0, sizeof(list)); + memset(tunnel, 0, sizeof(tunnel)); + + if((in = fopen(filename, "rb")) == NULL) + return -2; + + if((client = ilclient_init()) == NULL) + { + fclose(in); + return -3; + } + + if(OMX_Init() != OMX_ErrorNone) + { + ilclient_destroy(client); + fclose(in); + 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; + + + { +OMX_PARAM_PORTDEFINITIONTYPE portdef; + portdef.nSize = sizeof (OMX_PARAM_PORTDEFINITIONTYPE); + portdef.nVersion.nVersion = OMX_VERSION; + portdef.nPortIndex = 130; + if (OMX_GetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamPortDefinition, &portdef) == OMX_ErrorNone) { + portdef.nBufferCountActual = 20;//portdef.nBufferCountMin; + //portdef.nBufferSize = 16*1024 ;//32 * 1024; + printf("OMX_GetParameter nBufferCount %d nBufferSize %d\n",portdef.nBufferCountActual,portdef.nBufferSize); + + /*if (OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamPortDefinition, &portdef) != OMX_ErrorNone) { + printf("OMX_SetParameter error\n"); + }*/ + } +} + + 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); + + 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; + #define BURST_READ (500) + data_len = fread(dest, 1, BURST_READ, in); + //printf("Lu = %d\n",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; + printf("First Packet %llu\n",FromOMXTime(buf->nTimeStamp)); + } + else + { static uint64_t PTS=0; + + //buf->nTimeStamp = ToOMXTime(PTS); + buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN; + //buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; + PTS+=40*90*300L; + + } + + 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); + + // need to flush the renderer to allow video_decode to disable its input port + ilclient_flush_tunnels(tunnel, 0); + + } + + fclose(in); + + 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) +{ + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + exit(1); + } + bcm_host_init(); + return video_decode_test(argv[1]); +} + +