├── VS2005WS ├── UDPSAMPLE.suo ├── UDPSAMPLE.sln └── UDPSAMPLE.vcproj ├── AUTHORS ├── stdafx.cpp ├── stdafx.h ├── PATENTS ├── LICENSE ├── rtp.h ├── time.c ├── tctypes.h ├── Makefile ├── qedit.h ├── README ├── uvc_compat.h ├── uvcvideo.h ├── vpx_network.h ├── grabcompressandsend.cpp └── receivedecompressandplay.cpp /VS2005WS/UDPSAMPLE.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webmproject/udpsample/HEAD/VS2005WS/UDPSAMPLE.suo -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This file is automatically generated from the git commit history 2 | # by tools/gen_authors.sh. 3 | 4 | Jim Bankoski 5 | -------------------------------------------------------------------------------- /stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // UDPSAMPLE.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. 9 | #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. 10 | #endif 11 | 12 | #include 13 | #include 14 | 15 | 16 | 17 | // TODO: reference additional headers your program requires here 18 | -------------------------------------------------------------------------------- /VS2005WS/UDPSAMPLE.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 9.00 3 | # Visual Studio 2005 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UDPSAMPLE", "UDPSAMPLE.vcproj", "{1BA1039F-4A01-47EC-85C6-1EB7861B95ED}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | GrabCompressAndSend|Win32 = GrabCompressAndSend|Win32 9 | ReceiveDecompressAndPlay|Win32 = ReceiveDecompressAndPlay|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {1BA1039F-4A01-47EC-85C6-1EB7861B95ED}.GrabCompressAndSend|Win32.ActiveCfg = GrabCompressAndSend|Win32 13 | {1BA1039F-4A01-47EC-85C6-1EB7861B95ED}.GrabCompressAndSend|Win32.Build.0 = GrabCompressAndSend|Win32 14 | {1BA1039F-4A01-47EC-85C6-1EB7861B95ED}.ReceiveDecompressAndPlay|Win32.ActiveCfg = ReceiveDecompressAndPlay|Win32 15 | {1BA1039F-4A01-47EC-85C6-1EB7861B95ED}.ReceiveDecompressAndPlay|Win32.Build.0 = ReceiveDecompressAndPlay|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | ------------------------------------ 3 | 4 | "These implementations" means the copyrightable works that implement the WebM 5 | codecs distributed by Google as part of the WebM Project. 6 | 7 | Google hereby grants to you a perpetual, worldwide, non-exclusive, no-charge, 8 | royalty-free, irrevocable (except as stated in this section) patent license to 9 | make, have made, use, offer to sell, sell, import, transfer, and otherwise 10 | run, modify and propagate the contents of these implementations of WebM, where 11 | such license applies only to those patent claims, both currently owned by 12 | Google and acquired in the future, licensable by Google that are necessarily 13 | infringed by these implementations of WebM. This grant does not include claims 14 | that would be infringed only as a consequence of further modification of these 15 | implementations. If you or your agent or exclusive licensee institute or order 16 | or agree to the institution of patent litigation or any other patent 17 | enforcement activity against any entity (including a cross-claim or 18 | counterclaim in a lawsuit) alleging that any of these implementations of WebM 19 | or any code incorporated within any of these implementations of WebM 20 | constitute direct or contributory patent infringement, or inducement of 21 | patent infringement, then any patent rights granted to you under this License 22 | for these implementations of WebM shall terminate as of the date such 23 | litigation is filed. 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Google Inc. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the 13 | distribution. 14 | 15 | * Neither the name of Google nor the names of its contributors may 16 | be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | -------------------------------------------------------------------------------- /rtp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #define LARGESTFRAMESIZE 1000000 12 | #define PACKET_SIZE 1370 13 | 14 | typedef enum { 15 | VPX_VP8, 16 | VPX_VP9 17 | } CODEC; 18 | 19 | enum { 20 | DATAPACKET = 0, 21 | XORPACKET = 1, 22 | }; 23 | enum { 24 | NORMAL = 0, 25 | KEY = 1, 26 | GOLD = 2, 27 | ALTREF = 3 28 | }; 29 | enum { 30 | LOG_PACKET = 1, 31 | SKIP = 2, 32 | REBUILD = 4, 33 | DISCARD = 8, 34 | FRAME = 16, 35 | ERRORS = 32, 36 | }; 37 | 38 | //#define LOG_MASK ( ERRORS |REBUILD|DISCARD|LOG_PACKET|SKIP|FRAME) 39 | 40 | #define LOG_MASK (ERRORS) 41 | #define R2(X) ( (((X) & 0xff) << 8) | ((X) >> 8) ) 42 | #define R4(X) ( ((X & 0xff) << 24) | ((X & 0xff00) << 8) | \ 43 | ((X & 0xff0000) >> 8) | (X >> 24) ) 44 | typedef struct { 45 | int version :2; 46 | int pad :1; 47 | int extension :1; 48 | int csrccount :4; 49 | int marker :1; 50 | int payloadtype :7; 51 | unsigned short seq; 52 | unsigned int timestamp; 53 | 54 | unsigned int ssrc; 55 | unsigned int csrc; // repeated up to 15 times 56 | 57 | unsigned int type :1; 58 | unsigned int redundant_count :3; 59 | unsigned int new_frame :1; 60 | unsigned int end_frame :1; 61 | unsigned int frame_type :2; 62 | 63 | unsigned char data[PACKET_SIZE]; 64 | 65 | // this value doesn't actually get written or read 66 | unsigned int size; 67 | 68 | } PACKET; 69 | 70 | #define PACKET_HEADER_SIZE offsetof(PACKET,data) 71 | 72 | unsigned int get_time(void); 73 | void vpxlog_dbg_no_head(int level, const tc8 *format, ...); 74 | void vpxlog_dbg(int level, const tc8 *format, ...); 75 | -------------------------------------------------------------------------------- /time.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | 12 | #ifdef WINDOWS 13 | #include 14 | #include 15 | unsigned int get_time(void) 16 | { 17 | LARGE_INTEGER pf; 18 | long long now; 19 | QueryPerformanceCounter((LARGE_INTEGER *) &now); 20 | QueryPerformanceFrequency(&pf); 21 | return (unsigned int)(now * 1000 / pf.LowPart); 22 | } 23 | #else 24 | #include 25 | #include 26 | 27 | unsigned int get_time(void) 28 | { 29 | struct timespec ts; 30 | unsigned long long tv; 31 | 32 | #if _POSIX_TIMERS > 0 33 | clock_gettime(CLOCK_REALTIME, &ts); 34 | #else 35 | struct timeval tv2; 36 | gettimeofday(&tv2, NULL); 37 | ts.tv_sec = tv2.tv_sec; 38 | ts.tv_nsec = tv2.tv_usec * 1000; 39 | #endif 40 | tv = ts.tv_sec * 1000 + ts.tv_nsec / 1000000; 41 | return tv & 0xffffffff; 42 | } 43 | int _kbhit(void) 44 | { 45 | struct timeval tv; 46 | fd_set read_fd; 47 | 48 | tv.tv_sec = 0; 49 | tv.tv_usec = 0; 50 | FD_ZERO(&read_fd); 51 | FD_SET(0, &read_fd); 52 | 53 | if (select(1, &read_fd, NULL, NULL, &tv) == -1) 54 | return 0; 55 | 56 | if (FD_ISSET(0, &read_fd)) 57 | return 1; 58 | 59 | return 0; 60 | } 61 | 62 | 63 | #endif 64 | 65 | #include "tctypes.h" 66 | #include "rtp.h" 67 | #include 68 | #include 69 | 70 | unsigned int start_time = 0; 71 | 72 | void vpxlog_dbg_no_head(int level, const tc8 *format, ...) 73 | { 74 | va_list list; 75 | 76 | if (!(level & LOG_MASK)) 77 | return; 78 | 79 | va_start(list, format); 80 | 81 | vprintf(format, list); 82 | va_end(list); 83 | } 84 | 85 | void vpxlog_dbg(int level, const tc8 *format, ...) 86 | { 87 | va_list list; 88 | 89 | if (!(level & LOG_MASK)) 90 | return; 91 | 92 | if (start_time == 0) 93 | start_time = get_time(); 94 | 95 | printf("%8d ", get_time() - start_time); 96 | va_start(list, format); 97 | 98 | vprintf(format, list); 99 | va_end(list); 100 | } 101 | 102 | -------------------------------------------------------------------------------- /tctypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #ifndef __TCTYPES_H__ 12 | #define __TCTYPES_H__ 13 | 14 | /* basic types */ 15 | 16 | typedef char tc8; 17 | typedef unsigned char tcu8; 18 | typedef short tc16; 19 | typedef unsigned short tcu16; 20 | typedef int tc32; 21 | typedef unsigned int tcu32; 22 | 23 | #if defined(LINUX) 24 | # define TC64 "lld" 25 | typedef long long tc64; 26 | #elif defined(WIN32) || defined(_WIN32_WCE) 27 | # define TC64 "I64d" 28 | typedef __int64 tc64; 29 | #elif defined(VXWORKS) || defined(NDS_NITRO) 30 | # define TC64 "lld" 31 | typedef long long tc64; 32 | #elif defined(__uClinux__) && defined(CHIP_DM642) 33 | # include 34 | # define TC64 "lld" 35 | typedef long tc64; 36 | #elif defined(__SYMBIAN32__)&&!defined(__WINS__) 37 | #include "e32std.h" 38 | #define TC64 "lld" 39 | typedef TInt64 tc64; 40 | #elif defined(__SYMBIAN32__)&&defined(__WINS__) 41 | #define TC64 "lld" 42 | typedef long long tc64; 43 | #else 44 | #define TC64 "lld" 45 | typedef long long tc64; 46 | #endif 47 | 48 | #ifndef __SYMBIAN32__ 49 | /*not carrying over the I64INT as it actually has the potential to change the 50 | calculation as it effectively casts to int*/ 51 | # define I64REAL(x) ((double)(x)) 52 | #endif 53 | 54 | #define tcFalse 0 55 | #define tcTrue 1 56 | 57 | /* END - basic types */ 58 | 59 | /* TrueCast return codes; common to all libs */ 60 | 61 | enum eTCRV 62 | { 63 | TC_FILE_NOT_FOUND = -404, 64 | 65 | TC_BUFFER_UNDERRUN = -203, 66 | TC_BUFFER_EMPTY = -202, 67 | TC_BUFFER_FULL = -201, 68 | 69 | TC_MSG_TOO_LARGE = -102, 70 | TC_TIMEDOUT = -101, 71 | TC_WOULDBLOCK = -100, 72 | 73 | TC_INVALID_VERSION = -8, 74 | TC_INPROGRESS = -7, 75 | TC_INVALID_STATE_CHANGE = -6, 76 | TC_NO_PLUGIN = -5, 77 | TC_RESOURCE_LOCKED = -4, 78 | TC_NO_MEM = -3, 79 | TC_INVALID_PARAMS = -2, 80 | TC_ERROR = -1, 81 | TC_OK = 0, 82 | 83 | TC_DONE = 1 84 | }; 85 | typedef enum eTCRV TCRV; 86 | 87 | #endif //__TCTYPES_H__ 88 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | RM := rm -rf 2 | 3 | # All of the sources participating in the build are defined here 4 | CPP_SRCS := \ 5 | grabcompressandsend.cpp \ 6 | receivedecompressandplay.cpp 7 | 8 | C_SRCS := \ 9 | time.c \ 10 | vpx_network.c 11 | 12 | OBJS := \ 13 | time.o \ 14 | vpx_network.o 15 | 16 | CPP_DEPS := \ 17 | ./grabcompressandsend.d \ 18 | ./receivedecompressandplay.d 19 | 20 | C_DEPS := \ 21 | ./time.d \ 22 | ./vpx_network.d 23 | 24 | UNAME := $(shell uname) 25 | 26 | ifeq ($(UNAME), Linux) 27 | C_FLAGS = -DLINUX -O3 -g3 -Wall -c -fmessage-length=0 -m64 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" 28 | RLIBS := -lvpx -lpthread -lrt -lSDL2 29 | SLIBS := -lvpx -lpthread -lrt 30 | L_FLAGS := -m64 31 | else 32 | ifeq ($(UNAME), Darwin) 33 | C_FLAGS = -DLINUX -DMACOSX -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" 34 | RLIBS := -lvpx -lpthread -lSDL2 -lpthread -lSDLmain -framework cocoa 35 | SLIBS := -framework Carbon -framework QuartzCore -framework QuickTime -lvpx -lpthread -framework cocoa -lvidcap 36 | L_FLAGS := -D_THREAD_SAFE 37 | else 38 | ifneq ($(findstring CYGWIN, $(UNAME)),) 39 | C_FLAGS = -DLINUX -DMACOSX -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" 40 | RLIBS := -lvpx -lpthread -lrt -lSDL2 41 | SLIBS := -lvpx -lpthread -lrt -lvidcap 42 | L_FLAGS := 43 | else 44 | $(error Unknown System need to fix this make file!) 45 | endif 46 | endif 47 | endif 48 | EXECUTABLES := grabcompressandsend receivedecompressandplay 49 | 50 | 51 | # Each subdirectory must supply rules for building sources it contributes 52 | %.o: %.cpp 53 | @echo 'Building file: $<' 54 | @echo 'Invoking: GCC C++ Compiler' 55 | g++ $(C_FLAGS) -o"$@" "$<" 56 | @echo 'Finished building: $<' 57 | @echo ' ' 58 | 59 | %.o: %.c 60 | @echo 'Building file: $<' 61 | @echo 'Invoking: GCC C Compiler' 62 | gcc $(C_FLAGS) -o"$@" "$<" 63 | @echo 'Finished building: $<' 64 | @echo ' ' 65 | 66 | 67 | 68 | # Add inputs and outputs from these tool invocations to the build variables 69 | 70 | # All Target 71 | all: grabcompressandsend receivedecompressandplay 72 | 73 | # Tool invocations 74 | grabcompressandsend: $(OBJS) $(USER_OBJS) ./grabcompressandsend.o 75 | @echo 'Building target: $@' 76 | @echo 'Invoking: GCC C++ Linker' 77 | @echo g++ $(L_FLAGS) -o "grabcompressandsend" ./grabcompressandsend.o $(OBJS) $(SLIBS) 78 | g++ $(L_FLAGS) -o "grabcompressandsend" ./grabcompressandsend.o $(OBJS) $(SLIBS) 79 | @echo 'Finished building target: $@' 80 | @echo ' ' 81 | 82 | receivedecompressandplay: $(OBJS) $(USER_OBJS) ./receivedecompressandplay.o 83 | @echo 'Building target: $@' 84 | @echo 'Invoking: GCC C++ Linker' 85 | g++ $(L_FLAGS) -o "receivedecompressandplay" ./receivedecompressandplay.o $(OBJS) $(RLIBS) 86 | @echo 'Finished building target: $@' 87 | @echo ' ' 88 | 89 | 90 | # Other Targets 91 | clean: 92 | -$(RM) $(OBJS) $(C_DEPS) $(CPP_DEPS) $(EXECUTABLES) receivedecompressandplay.o grabcompressandsend.o 93 | -@echo ' ' 94 | 95 | 96 | -------------------------------------------------------------------------------- /qedit.h: -------------------------------------------------------------------------------- 1 | #ifndef __qedit_h__ 2 | #define __qedit_h__ 3 | 4 | /////////////////////////////////////////////////////////////////////////////////// 5 | 6 | #pragma once 7 | 8 | /////////////////////////////////////////////////////////////////////////////////// 9 | interface 10 | ISampleGrabberCB 11 | : 12 | public IUnknown 13 | { 14 | virtual STDMETHODIMP SampleCB(double SampleTime, IMediaSample *pSample) = 0; 15 | virtual STDMETHODIMP BufferCB(double SampleTime, BYTE *pBuffer, long BufferLen) = 0; 16 | }; 17 | 18 | /////////////////////////////////////////////////////////////////////////////////// 19 | 20 | 21 | IID IID_ISampleGrabberCB = { 0x0579154A, 0x2B53, 0x4994, { 0xB0, 0xD0, 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85 } }; 22 | 23 | /////////////////////////////////////////////////////////////////////////////////// 24 | 25 | interface 26 | ISampleGrabber 27 | : 28 | public IUnknown 29 | { 30 | virtual HRESULT STDMETHODCALLTYPE SetOneShot(BOOL OneShot) = 0; 31 | virtual HRESULT STDMETHODCALLTYPE SetMediaType(const AM_MEDIA_TYPE *pType) = 0; 32 | virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType(AM_MEDIA_TYPE *pType) = 0; 33 | virtual HRESULT STDMETHODCALLTYPE SetBufferSamples(BOOL BufferThem) = 0; 34 | virtual HRESULT STDMETHODCALLTYPE GetCurrentBuffer(long *pBufferSize, long *pBuffer) = 0; 35 | virtual HRESULT STDMETHODCALLTYPE GetCurrentSample(IMediaSample **ppSample) = 0; 36 | virtual HRESULT STDMETHODCALLTYPE SetCallback(ISampleGrabberCB *pCallback, long WhichMethodToCallback) = 0; 37 | }; 38 | 39 | /////////////////////////////////////////////////////////////////////////////////// 40 | 41 | static 42 | const 43 | IID IID_ISampleGrabber = { 0x6B652FFF, 0x11FE, 0x4fce, { 0x92, 0xAD, 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F } }; 44 | 45 | /////////////////////////////////////////////////////////////////////////////////// 46 | 47 | static 48 | const 49 | CLSID CLSID_SampleGrabber = { 0xC1F400A0, 0x3F08, 0x11d3, { 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 } }; 50 | 51 | /////////////////////////////////////////////////////////////////////////////////// 52 | 53 | static 54 | const 55 | CLSID CLSID_NullRenderer = { 0xC1F400A4, 0x3F08, 0x11d3, { 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 } }; 56 | 57 | /////////////////////////////////////////////////////////////////////////////////// 58 | 59 | static 60 | const 61 | CLSID CLSID_VideoEffects1Category = { 0xcc7bfb42, 0xf175, 0x11d1, { 0xa3, 0x92, 0x0, 0xe0, 0x29, 0x1f, 0x39, 0x59 } }; 62 | 63 | /////////////////////////////////////////////////////////////////////////////////// 64 | 65 | static 66 | const 67 | CLSID CLSID_VideoEffects2Category = { 0xcc7bfb43, 0xf175, 0x11d1, { 0xa3, 0x92, 0x0, 0xe0, 0x29, 0x1f, 0x39, 0x59 } }; 68 | 69 | /////////////////////////////////////////////////////////////////////////////////// 70 | 71 | static 72 | const 73 | CLSID CLSID_AudioEffects1Category = { 0xcc7bfb44, 0xf175, 0x11d1, { 0xa3, 0x92, 0x0, 0xe0, 0x29, 0x1f, 0x39, 0x59 } }; 74 | 75 | /////////////////////////////////////////////////////////////////////////////////// 76 | 77 | static 78 | const 79 | CLSID CLSID_AudioEffects2Category = { 0xcc7bfb45, 0xf175, 0x11d1, { 0xa3, 0x92, 0x0, 0xe0, 0x29, 0x1f, 0x39, 0x59 } }; 80 | 81 | /////////////////////////////////////////////////////////////////////////////////// 82 | 83 | #endif 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | UDPSample 2 | =============== 3 | 4 | This sample illustrates using vp8 for a live video transmission over lossy 5 | UDP with a back channel. 6 | 7 | It includes two sample console based subprograms: 8 | 9 | 10 | GrabCompressAndSend 11 | upon receipt of session initiation requests from ReceiveDecompressAndPlay, 12 | captures live video from an installed direct show camera, compresses it, 13 | packetizes it, adds forward error correction (if specified) and then sends 14 | the data across a port using UDP. Upon any receipt of a request for recovery 15 | or for a packet resend it responds appropriately. 16 | 17 | ReceiveDecompressAndPlay 18 | initiates a session with GrabCompressAndSend sending parameters regarding 19 | forward error correction, simulated packetloss, datarate, frame size, etc. 20 | The program then awaits arrival of packets from GrabCompressAndSend and uses 21 | them to reassemble frames, which it then decompress and plays for the user. 22 | Any lost packets that can be rebuilt using forward error correction are 23 | rebuilt. If a packet is lost and can't be rebuilt, packet resend requests 24 | are sent. If there is still not a timely response or a large number of 25 | packets are lost the program requests a recovery frame. 26 | 27 | Build requirements : 28 | 29 | Linux -> 64-bit, libsdl and libvpx must be installed and in your paths. 30 | MacOSX -> libsdk, libvpx and libvidcap must be installed and in your paths. 31 | Windows -> VS2005, PlatformSDK ( + DirectShow Baseclasses ) in include and lib 32 | path, DirectX in include and libpath 33 | 34 | DISCLAIMER: This sample code has only been tested on a very limited set of 35 | machines - we can use your help to expand and make it work on a wider range 36 | of platforms. 37 | 38 | 39 | 40 | ============================================================ 41 | Usage: Open up two command prompt windows. in one run : 42 | 43 | grabcompressandsend 44 | 45 | in the other run 46 | 47 | receivedecompressandplay 48 | 49 | Two video windows should open and video should be played. 50 | 51 | 52 | On 2 separate computers the following command lines requests 400 kbps 53 | 960x720 video compressed at 15fps, to be sent with 1 xor-packet created from 54 | every 5 packets over ports 1407 and 1408. Recovery frames are requested if a 55 | lost packet ages to 800 ms. 56 | 57 | receivedecompressandplay -w 960 -h 720 -f 15 -b 400 -n 6 -d 5 -t 800 -s 1408 -r 1407 58 | 59 | grabcompressandsend -i 10.10.28.1 -s 1407 -r 1408 60 | 61 | ============================================================ 62 | 63 | ReceiveDecompressAndPlay has the following other options: 64 | 65 | -w [640] request capture width 66 | -h [480] request capture height 67 | -f [30] request capture frame rate 68 | -b [300] videoBitrate = ato 69 | -n [6] fecNumerator ( redundancy numerator) 70 | -d [5] fecDenominator ( redundancy denominator) 71 | 6/5 means 1 xor packet for every 5 packets, 72 | 4/1 means 3 duplicate packets for every packet 73 | -t [800] milliseconds before giving up and requesting recovery 74 | -i [50] time in milliseconds between attempts at a packet resend 75 | -c [12] number of lost packets before requesting recovery 76 | -l [0] packets to lose out of every 1000 77 | -s [1408] port to send requests to 78 | -r [1407] port to receive requests on. 79 | 80 | 81 | GrabCompressAndSend has the following options: 82 | 83 | -i [127.0.0.1] Port to send data to. 84 | -s [1408] port to send requests to 85 | -r [1407] port to receive requests on. 86 | 87 | 88 | 89 | Caveats: This is just sample code. There are many problems that this 90 | code does not make any attempt at all to resolve. Ie. Getting through 91 | firewalls, sensible session initiation (IE SIP), responding to datarate 92 | or packetloss fluctuation, keeping audio and video and synch. Nor does it 93 | resolve issues like long term dropouts or other common problems in any 94 | ensible way. The handling of packets and skipped packets is rudimentary 95 | with extra copies, and a very rudimentary way of handling skips. The program 96 | requires directx7 or better with yv12 offscreen surfaces for decode, and a web 97 | camera / capture device capable of supplying i420. Basic RTP is used but RTCP 98 | isn't. 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /uvc_compat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #ifndef _UVC_COMPAT_H 12 | #define _UVC_COMPAT_H 13 | 14 | #include 15 | 16 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) 17 | /* 18 | * Extended control API 19 | */ 20 | struct v4l2_ext_control 21 | { 22 | __u32 id; 23 | __u32 reserved2[2]; 24 | union 25 | { 26 | __s32 value; 27 | __s64 value64; 28 | void *reserved; 29 | }; 30 | } __attribute__((packed)); 31 | 32 | struct v4l2_ext_controls 33 | { 34 | __u32 ctrl_class; 35 | __u32 count; 36 | __u32 error_idx; 37 | __u32 reserved[2]; 38 | struct v4l2_ext_control *controls; 39 | }; 40 | 41 | /* Values for ctrl_class field */ 42 | #define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */ 43 | #define V4L2_CTRL_CLASS_MPEG 0x00990000 /* MPEG-compression controls */ 44 | 45 | #define V4L2_CTRL_ID_MASK (0x0fffffff) 46 | #define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL) 47 | #define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000) 48 | 49 | /* User-class control IDs defined by V4L2 */ 50 | #undef V4L2_CID_BASE 51 | #define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900) 52 | #define V4L2_CID_USER_BASE V4L2_CID_BASE 53 | #define V4L2_CID_USER_CLASS (V4L2_CTRL_CLASS_USER | 1) 54 | 55 | #define VIDIOC_G_EXT_CTRLS _IOWR ('V', 71, struct v4l2_ext_controls) 56 | #define VIDIOC_S_EXT_CTRLS _IOWR ('V', 72, struct v4l2_ext_controls) 57 | #define VIDIOC_TRY_EXT_CTRLS _IOWR ('V', 73, struct v4l2_ext_controls) 58 | 59 | #endif 60 | 61 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) 62 | /* 63 | * Frame size and frame rate enumeration 64 | * 65 | * Included in Linux 2.6.19 66 | */ 67 | enum v4l2_frmsizetypes 68 | { 69 | V4L2_FRMSIZE_TYPE_DISCRETE = 1, 70 | V4L2_FRMSIZE_TYPE_CONTINUOUS = 2, 71 | V4L2_FRMSIZE_TYPE_STEPWISE = 3, 72 | }; 73 | 74 | struct v4l2_frmsize_discrete 75 | { 76 | __u32 width; /* Frame width [pixel] */ 77 | __u32 height; /* Frame height [pixel] */ 78 | }; 79 | 80 | struct v4l2_frmsize_stepwise 81 | { 82 | __u32 min_width; /* Minimum frame width [pixel] */ 83 | __u32 max_width; /* Maximum frame width [pixel] */ 84 | __u32 step_width; /* Frame width step size [pixel] */ 85 | __u32 min_height; /* Minimum frame height [pixel] */ 86 | __u32 max_height; /* Maximum frame height [pixel] */ 87 | __u32 step_height; /* Frame height step size [pixel] */ 88 | }; 89 | 90 | struct v4l2_frmsizeenum 91 | { 92 | __u32 index; /* Frame size number */ 93 | __u32 pixel_format; /* Pixel format */ 94 | __u32 type; /* Frame size type the device supports. */ 95 | 96 | union /* Frame size */ 97 | { 98 | struct v4l2_frmsize_discrete discrete; 99 | struct v4l2_frmsize_stepwise stepwise; 100 | }; 101 | 102 | __u32 reserved[2]; /* Reserved space for future use */ 103 | }; 104 | 105 | enum v4l2_frmivaltypes 106 | { 107 | V4L2_FRMIVAL_TYPE_DISCRETE = 1, 108 | V4L2_FRMIVAL_TYPE_CONTINUOUS = 2, 109 | V4L2_FRMIVAL_TYPE_STEPWISE = 3, 110 | }; 111 | 112 | struct v4l2_frmival_stepwise 113 | { 114 | struct v4l2_fract min; /* Minimum frame interval [s] */ 115 | struct v4l2_fract max; /* Maximum frame interval [s] */ 116 | struct v4l2_fract step; /* Frame interval step size [s] */ 117 | }; 118 | 119 | struct v4l2_frmivalenum 120 | { 121 | __u32 index; /* Frame format index */ 122 | __u32 pixel_format; /* Pixel format */ 123 | __u32 width; /* Frame width */ 124 | __u32 height; /* Frame height */ 125 | __u32 type; /* Frame interval type the device supports. */ 126 | 127 | union /* Frame interval */ 128 | { 129 | struct v4l2_fract discrete; 130 | struct v4l2_frmival_stepwise stepwise; 131 | }; 132 | 133 | __u32 reserved[2]; /* Reserved space for future use */ 134 | }; 135 | 136 | #define VIDIOC_ENUM_FRAMESIZES _IOWR ('V', 74, struct v4l2_frmsizeenum) 137 | #define VIDIOC_ENUM_FRAMEINTERVALS _IOWR ('V', 75, struct v4l2_frmivalenum) 138 | #endif 139 | 140 | 141 | #endif /* _UVC_COMPAT_H */ 142 | 143 | -------------------------------------------------------------------------------- /VS2005WS/UDPSAMPLE.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 27 | 30 | 33 | 36 | 39 | 42 | 56 | 59 | 62 | 65 | 77 | 80 | 83 | 86 | 89 | 92 | 95 | 98 | 101 | 102 | 111 | 114 | 117 | 120 | 123 | 126 | 140 | 143 | 146 | 149 | 161 | 164 | 167 | 170 | 173 | 176 | 179 | 182 | 185 | 186 | 187 | 188 | 189 | 190 | 195 | 198 | 202 | 205 | 206 | 207 | 210 | 214 | 217 | 218 | 219 | 222 | 223 | 226 | 227 | 230 | 231 | 232 | 237 | 240 | 241 | 244 | 245 | 248 | 249 | 252 | 253 | 256 | 257 | 260 | 261 | 264 | 265 | 268 | 269 | 272 | 273 | 274 | 279 | 280 | 281 | 282 | 283 | 284 | -------------------------------------------------------------------------------- /uvcvideo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #ifndef _USB_VIDEO_H_ 12 | #define _USB_VIDEO_H_ 13 | 14 | #include 15 | #include 16 | 17 | /* Compatibility */ 18 | #include "uvc_compat.h" 19 | 20 | /* 21 | * Private V4L2 control identifiers. 22 | */ 23 | 24 | #if not defined(V4L2_CID_BACKLIGHT_COMPENSATION) 25 | #define V4L2_CID_BACKLIGHT_COMPENSATION (V4L2_CID_PRIVATE_BASE+0) 26 | #define V4L2_CID_POWER_LINE_FREQUENCY (V4L2_CID_PRIVATE_BASE+1) 27 | #define V4L2_CID_SHARPNESS (V4L2_CID_PRIVATE_BASE+2) 28 | #define V4L2_CID_HUE_AUTO (V4L2_CID_PRIVATE_BASE+3) 29 | 30 | #define V4L2_CID_FOCUS_AUTO (V4L2_CID_PRIVATE_BASE+4) 31 | #define V4L2_CID_FOCUS_ABSOLUTE (V4L2_CID_PRIVATE_BASE+5) 32 | #define V4L2_CID_FOCUS_RELATIVE (V4L2_CID_PRIVATE_BASE+6) 33 | 34 | #define V4L2_CID_PAN_RELATIVE (V4L2_CID_PRIVATE_BASE+7) 35 | #define V4L2_CID_TILT_RELATIVE (V4L2_CID_PRIVATE_BASE+8) 36 | #define V4L2_CID_PANTILT_RESET (V4L2_CID_PRIVATE_BASE+9) 37 | 38 | #define V4L2_CID_EXPOSURE_AUTO (V4L2_CID_PRIVATE_BASE+10) 39 | #define V4L2_CID_EXPOSURE_ABSOLUTE (V4L2_CID_PRIVATE_BASE+11) 40 | 41 | #define V4L2_CID_WHITE_BALANCE_TEMPERATURE_AUTO (V4L2_CID_PRIVATE_BASE+12) 42 | #define V4L2_CID_WHITE_BALANCE_TEMPERATURE (V4L2_CID_PRIVATE_BASE+13) 43 | 44 | #endif 45 | 46 | #define V4L2_CID_PRIVATE_LAST V4L2_CID_WHITE_BALANCE_TEMPERATURE 47 | 48 | #ifdef __KERNEL__ 49 | 50 | /* -------------------------------------------------------------------------- 51 | * UVC constants 52 | */ 53 | 54 | #define SC_UNDEFINED 0x00 55 | #define SC_VIDEOCONTROL 0x01 56 | #define SC_VIDEOSTREAMING 0x02 57 | #define SC_VIDEO_INTERFACE_COLLECTION 0x03 58 | 59 | #define PC_PROTOCOL_UNDEFINED 0x00 60 | 61 | #define CS_UNDEFINED 0x20 62 | #define CS_DEVICE 0x21 63 | #define CS_CONFIGURATION 0x22 64 | #define CS_STRING 0x23 65 | #define CS_INTERFACE 0x24 66 | #define CS_ENDPOINT 0x25 67 | 68 | /* VideoControl class specific interface descriptor */ 69 | #define VC_DESCRIPTOR_UNDEFINED 0x00 70 | #define VC_HEADER 0x01 71 | #define VC_INPUT_TERMINAL 0x02 72 | #define VC_OUTPUT_TERMINAL 0x03 73 | #define VC_SELECTOR_UNIT 0x04 74 | #define VC_PROCESSING_UNIT 0x05 75 | #define VC_EXTENSION_UNIT 0x06 76 | 77 | /* VideoStreaming class specific interface descriptor */ 78 | #define VS_UNDEFINED 0x00 79 | #define VS_INPUT_HEADER 0x01 80 | #define VS_OUTPUT_HEADER 0x02 81 | #define VS_STILL_IMAGE_FRAME 0x03 82 | #define VS_FORMAT_UNCOMPRESSED 0x04 83 | #define VS_FRAME_UNCOMPRESSED 0x05 84 | #define VS_FORMAT_MJPEG 0x06 85 | #define VS_FRAME_MJPEG 0x07 86 | #define VS_FORMAT_MPEG2TS 0x0a 87 | #define VS_FORMAT_DV 0x0c 88 | #define VS_COLORFORMAT 0x0d 89 | #define VS_FORMAT_FRAME_BASED 0x10 90 | #define VS_FRAME_FRAME_BASED 0x11 91 | #define VS_FORMAT_STREAM_BASED 0x12 92 | 93 | /* Endpoint type */ 94 | #define EP_UNDEFINED 0x00 95 | #define EP_GENERAL 0x01 96 | #define EP_ENDPOINT 0x02 97 | #define EP_INTERRUPT 0x03 98 | 99 | /* Request codes */ 100 | #define RC_UNDEFINED 0x00 101 | #define SET_CUR 0x01 102 | #define GET_CUR 0x81 103 | #define GET_MIN 0x82 104 | #define GET_MAX 0x83 105 | #define GET_RES 0x84 106 | #define GET_LEN 0x85 107 | #define GET_INFO 0x86 108 | #define GET_DEF 0x87 109 | 110 | /* VideoControl interface controls */ 111 | #define VC_CONTROL_UNDEFINED 0x00 112 | #define VC_VIDEO_POWER_MODE_CONTROL 0x01 113 | #define VC_REQUEST_ERROR_CODE_CONTROL 0x02 114 | 115 | /* Terminal controls */ 116 | #define TE_CONTROL_UNDEFINED 0x00 117 | 118 | /* Selector Unit controls */ 119 | #define SU_CONTROL_UNDEFINED 0x00 120 | #define SU_INPUT_SELECT_CONTROL 0x01 121 | 122 | /* Camera Terminal controls */ 123 | #define CT_CONTROL_UNDEFINED 0x00 124 | #define CT_SCANNING_MODE_CONTROL 0x01 125 | #define CT_AE_MODE_CONTROL 0x02 126 | #define CT_AE_PRIORITY_CONTROL 0x03 127 | #define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04 128 | #define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05 129 | #define CT_FOCUS_ABSOLUTE_CONTROL 0x06 130 | #define CT_FOCUS_RELATIVE_CONTROL 0x07 131 | #define CT_FOCUS_AUTO_CONTROL 0x08 132 | #define CT_IRIS_ABSOLUTE_CONTROL 0x09 133 | #define CT_IRIS_RELATIVE_CONTROL 0x0a 134 | #define CT_ZOOM_ABSOLUTE_CONTROL 0x0b 135 | #define CT_ZOOM_RELATIVE_CONTROL 0x0c 136 | #define CT_PANTILT_ABSOLUTE_CONTROL 0x0d 137 | #define CT_PANTILT_RELATIVE_CONTROL 0x0e 138 | #define CT_ROLL_ABSOLUTE_CONTROL 0x0f 139 | #define CT_ROLL_RELATIVE_CONTROL 0x10 140 | #define CT_PRIVACY_CONTROL 0x11 141 | 142 | /* Processing Unit controls */ 143 | #define PU_CONTROL_UNDEFINED 0x00 144 | #define PU_BACKLIGHT_COMPENSATION_CONTROL 0x01 145 | #define PU_BRIGHTNESS_CONTROL 0x02 146 | #define PU_CONTRAST_CONTROL 0x03 147 | #define PU_GAIN_CONTROL 0x04 148 | #define PU_POWER_LINE_FREQUENCY_CONTROL 0x05 149 | #define PU_HUE_CONTROL 0x06 150 | #define PU_SATURATION_CONTROL 0x07 151 | #define PU_SHARPNESS_CONTROL 0x08 152 | #define PU_GAMMA_CONTROL 0x09 153 | #define PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a 154 | #define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b 155 | #define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c 156 | #define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d 157 | #define PU_DIGITAL_MULTIPLIER_CONTROL 0x0e 158 | #define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f 159 | #define PU_HUE_AUTO_CONTROL 0x10 160 | #define PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11 161 | #define PU_ANALOG_LOCK_STATUS_CONTROL 0x12 162 | 163 | #define LXU_MOTOR_PANTILT_RELATIVE_CONTROL 0x01 164 | #define LXU_MOTOR_PANTILT_RESET_CONTROL 0x02 165 | 166 | /* VideoStreaming interface controls */ 167 | #define VS_CONTROL_UNDEFINED 0x00 168 | #define VS_PROBE_CONTROL 0x01 169 | #define VS_COMMIT_CONTROL 0x02 170 | #define VS_STILL_PROBE_CONTROL 0x03 171 | #define VS_STILL_COMMIT_CONTROL 0x04 172 | #define VS_STILL_IMAGE_TRIGGER_CONTROL 0x05 173 | #define VS_STREAM_ERROR_CODE_CONTROL 0x06 174 | #define VS_GENERATE_KEY_FRAME_CONTROL 0x07 175 | #define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08 176 | #define VS_SYNC_DELAY_CONTROL 0x09 177 | 178 | #define TT_VENDOR_SPECIFIC 0x0100 179 | #define TT_STREAMING 0x0101 180 | 181 | /* Input Terminal types */ 182 | #define ITT_VENDOR_SPECIFIC 0x0200 183 | #define ITT_CAMERA 0x0201 184 | #define ITT_MEDIA_TRANSPORT_INPUT 0x0202 185 | 186 | /* Output Terminal types */ 187 | #define OTT_VENDOR_SPECIFIC 0x0300 188 | #define OTT_DISPLAY 0x0301 189 | #define OTT_MEDIA_TRANSPORT_OUTPUT 0x0302 190 | 191 | #define EXTERNAL_VENDOR_SPECIFIC 0x0400 192 | #define COMPOSITE_CONNECTOR 0x0401 193 | #define SVIDEO_CONNECTOR 0x0402 194 | #define COMPONENT_CONNECTOR 0x0403 195 | 196 | #define UVC_ENTITY_IS_UNIT(entity) ((entity->type & 0xff00) == 0) 197 | #define UVC_ENTITY_IS_TERM(entity) ((entity->type & 0xff00) != 0) 198 | #define UVC_ENTITY_IS_ITERM(entity) ((entity->type & 0xff00) == ITT_VENDOR_SPECIFIC) 199 | #define UVC_ENTITY_IS_OTERM(entity) ((entity->type & 0xff00) == OTT_VENDOR_SPECIFIC) 200 | 201 | /* ------------------------------------------------------------------------ 202 | * GUIDs 203 | */ 204 | #define UVC_GUID_UVC_CAMERA {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 205 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} 206 | #define UVC_GUID_UVC_OUTPUT {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 207 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02} 208 | #define UVC_GUID_UVC_PROCESSING {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 209 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01} 210 | #define UVC_GUID_UVC_SELECTOR {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 211 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02} 212 | 213 | #define UVC_GUID_LOGITECH_XU1 {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \ 214 | 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1d} 215 | #define UVC_GUID_LOGITECH_XU2 {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \ 216 | 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1e} 217 | #define UVC_GUID_LOGITECH_XU3 {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \ 218 | 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1f} 219 | #define UVC_GUID_LOGITECH_MOTOR {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \ 220 | 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x56} 221 | #define UVC_GUID_LOGITECH_DEV_INFO \ 222 | {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \ 223 | 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1e} 224 | 225 | #define UVC_GUID_FORMAT_MJPEG {0x4d, 0x4a, 0x50, 0x47, 0x00, 0x00, 0x10, 0x00, \ 226 | 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} 227 | #define UVC_GUID_FORMAT_YUY2 {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, \ 228 | 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} 229 | #define UVC_GUID_FORMAT_NV12 {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, \ 230 | 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} 231 | 232 | 233 | /* ------------------------------------------------------------------------ 234 | * Driver specific constants. 235 | */ 236 | 237 | #define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0) 238 | 239 | /* Number of isochronous URBs. */ 240 | #define UVC_URBS 5 241 | /* Maximum number of packets per isochronous URB. */ 242 | #define UVC_MAX_ISO_PACKETS 40 243 | /* Maximum frame size in bytes, for sanity checking. */ 244 | #define UVC_MAX_FRAME_SIZE (16*1024*1024) 245 | /* Maximum number of video buffers. */ 246 | #define UVC_MAX_VIDEO_BUFFERS 32 247 | 248 | #define UVC_CTRL_TIMEOUT 300 249 | 250 | /* Devices quirks */ 251 | #define UVC_QUIRK_STATUS_INTERVAL 0x00000001 252 | 253 | /* ------------------------------------------------------------------------ 254 | * Structures. 255 | */ 256 | 257 | struct uvc_device; 258 | 259 | /* TODO: Put the most frequently accessed fields at the beginning of 260 | * structures to maximize cache efficiency. 261 | */ 262 | struct uvc_streaming_control 263 | { 264 | __u16 bmHint; 265 | __u8 bFormatIndex; 266 | __u8 bFrameIndex; 267 | __u32 dwFrameInterval; 268 | __u16 wKeyFrameRate; 269 | __u16 wPFrameRate; 270 | __u16 wCompQuality; 271 | __u16 wCompWindowSize; 272 | __u16 wDelay; 273 | __u32 dwMaxVideoFrameSize; 274 | __u32 dwMaxPayloadTransferSize; 275 | __u32 dwClockFrequency; 276 | __u8 bmFramingInfo; 277 | __u8 bPreferedVersion; 278 | __u8 bMinVersion; 279 | __u8 bMaxVersion; 280 | }; 281 | 282 | struct uvc_menu_info 283 | { 284 | __u32 index; 285 | __u8 name[32]; 286 | }; 287 | 288 | struct uvc_control_info 289 | { 290 | struct list_head list; 291 | struct list_head mappings; 292 | 293 | __u8 entity[16]; 294 | __u8 index; 295 | __u8 selector; 296 | 297 | __u8 size; 298 | __u8 flags; 299 | }; 300 | 301 | /* Data types for UVC control data */ 302 | enum uvc_control_data_type 303 | { 304 | UVC_CTRL_DATA_TYPE_RAW = 0, 305 | UVC_CTRL_DATA_TYPE_SIGNED, 306 | UVC_CTRL_DATA_TYPE_UNSIGNED, 307 | UVC_CTRL_DATA_TYPE_BOOLEAN, 308 | UVC_CTRL_DATA_TYPE_ENUM, 309 | UVC_CTRL_DATA_TYPE_BITMASK, 310 | }; 311 | 312 | struct uvc_control_mapping 313 | { 314 | struct list_head list; 315 | 316 | struct uvc_control_info *ctrl; 317 | 318 | __u32 id; 319 | __u8 name[32]; 320 | __u8 entity[16]; 321 | __u8 selector; 322 | 323 | __u8 size; 324 | __u8 offset; 325 | enum v4l2_ctrl_type v4l2_type; 326 | enum uvc_control_data_type data_type; 327 | 328 | struct uvc_menu_info *menu_info; 329 | __u32 menu_count; 330 | }; 331 | 332 | struct uvc_control 333 | { 334 | struct uvc_entity *entity; 335 | struct uvc_control_info *info; 336 | 337 | __u8 index; /* Used to match the uvc_control entry with a uvc_control_info. */ 338 | __u8 dirty : 1, 339 | loaded : 1; 340 | 341 | __u8 *data; 342 | }; 343 | 344 | struct uvc_format_desc 345 | { 346 | __u8 guid[16]; 347 | __u32 fcc; 348 | }; 349 | 350 | /* The term 'entity' refers to both UVC units and UVC terminals. 351 | * 352 | * The type field is either the terminal type (wTerminalType in the terminal 353 | * descriptor), or the unit type (bDescriptorSubtype in the unit descriptor). 354 | * As the bDescriptorSubtype field is one byte long, the type value will 355 | * always have a null MSB for units. All terminal types defined by the UVC 356 | * specification have a non-null MSB, so it is safe to use the MSB to 357 | * differentiate between units and terminals as long as the descriptor parsing 358 | * code makes sur terminal types have a non-null MSB. 359 | */ 360 | 361 | struct uvc_entity 362 | { 363 | struct list_head list; 364 | 365 | __u8 id; 366 | __u16 type; 367 | char name[64]; 368 | 369 | union 370 | { 371 | struct 372 | { 373 | __u16 wObjectiveFocalLengthMin; 374 | __u16 wObjectiveFocalLengthMax; 375 | __u16 wOcularFocalLength; 376 | __u8 bControlSize; 377 | __u8 *bmControls; 378 | } camera; 379 | 380 | struct 381 | { 382 | __u8 bSourceID; 383 | } output; 384 | 385 | struct 386 | { 387 | __u8 bSourceID; 388 | __u16 wMaxMultiplier; 389 | __u8 bControlSize; 390 | __u8 *bmControls; 391 | __u8 bmVideoStandards; 392 | } processing; 393 | 394 | struct 395 | { 396 | __u8 bNrInPins; 397 | __u8 *baSourceID; 398 | } selector; 399 | 400 | struct 401 | { 402 | __u8 guidExtensionCode[16]; 403 | __u8 bNumControls; 404 | __u8 bNrInPins; 405 | __u8 *baSourceID; 406 | __u8 bControlSize; 407 | __u8 *bmControls; 408 | __u8 *bmControlsType; 409 | } extension; 410 | }; 411 | 412 | unsigned int ncontrols; 413 | struct uvc_control *controls; 414 | }; 415 | 416 | struct uvc_frame 417 | { 418 | __u8 bFrameIndex; 419 | __u8 bmCapabilities; 420 | __u16 wWidth; 421 | __u16 wHeight; 422 | __u32 dwMinBitRate; 423 | __u32 dwMaxBitRate; 424 | __u32 dwMaxVideoFrameBufferSize; 425 | __u8 bFrameIntervalType; 426 | __u32 dwDefaultFrameInterval; 427 | __u32 *dwFrameInterval; 428 | }; 429 | 430 | struct uvc_format 431 | { 432 | __u8 type; 433 | __u8 index; 434 | __u8 bpp; 435 | __u8 colorspace; 436 | __u32 fcc; 437 | __u32 flags; 438 | 439 | char name[32]; 440 | 441 | unsigned int nframes; 442 | struct uvc_frame *frame; 443 | }; 444 | 445 | struct uvc_input_header 446 | { 447 | __u8 bNumFormats; 448 | __u8 bEndpointAddress; 449 | __u8 bmInfo; 450 | __u8 bTerminalLink; 451 | __u8 bStillCaptureMethod; 452 | __u8 bTriggerSupport; 453 | __u8 bTriggerUsage; 454 | __u8 bControlSize; 455 | __u8 *bmaControls; 456 | }; 457 | 458 | struct uvc_output_header 459 | { 460 | }; 461 | 462 | struct uvc_streaming 463 | { 464 | struct list_head list; 465 | 466 | struct usb_interface *intf; 467 | int intfnum; 468 | __u16 maxpsize; 469 | 470 | union 471 | { 472 | struct uvc_input_header input; 473 | struct uvc_output_header output; 474 | }; 475 | 476 | unsigned int nformats; 477 | struct uvc_format *format; 478 | 479 | struct uvc_streaming_control ctrl; 480 | struct uvc_format *cur_format; 481 | struct uvc_frame *cur_frame; 482 | 483 | struct mutex mutex; 484 | }; 485 | 486 | enum uvc_stream_state 487 | { 488 | UVC_STREAM_OFF = 0, 489 | UVC_STREAM_INTERRUPT = 1, 490 | UVC_STREAM_ON = 2, 491 | }; 492 | 493 | enum uvc_buffer_state 494 | { 495 | UVC_BUF_STATE_IDLE = 0, 496 | UVC_BUF_STATE_QUEUED = 1, 497 | UVC_BUF_STATE_ACTIVE = 2, 498 | UVC_BUF_STATE_DONE = 3, 499 | UVC_BUF_STATE_ERROR = 4, 500 | }; 501 | 502 | struct uvc_buffer 503 | { 504 | unsigned int size; 505 | unsigned long vma_use_count; 506 | struct list_head stream; 507 | 508 | /* Touched by interrupt handler. */ 509 | struct v4l2_buffer buf; 510 | struct list_head queue; 511 | wait_queue_head_t wait; 512 | enum uvc_buffer_state state; 513 | }; 514 | 515 | struct uvc_video_queue 516 | { 517 | void *mem; 518 | unsigned int streaming; 519 | __u32 sequence; 520 | __u8 last_fid; 521 | 522 | unsigned int count; 523 | struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS]; 524 | struct mutex mutex; 525 | spinlock_t irqlock; 526 | 527 | struct list_head mainqueue; 528 | struct list_head irqqueue; 529 | }; 530 | 531 | struct uvc_video_device 532 | { 533 | struct uvc_device *dev; 534 | struct video_device *vdev; 535 | atomic_t active; 536 | 537 | enum uvc_stream_state stream; 538 | 539 | struct uvc_entity *iterm; 540 | struct uvc_entity *oterm; 541 | struct uvc_entity *processing; 542 | struct uvc_entity *extension[8]; 543 | struct mutex ctrl_mutex; 544 | 545 | struct uvc_video_queue queue; 546 | 547 | struct uvc_streaming *streaming; 548 | 549 | struct urb *urb[UVC_URBS]; 550 | char *urb_buffer[UVC_URBS]; 551 | }; 552 | 553 | enum uvc_device_state 554 | { 555 | UVC_DEV_DISCONNECTED = 1, 556 | }; 557 | 558 | struct uvc_device 559 | { 560 | struct usb_device *udev; 561 | struct usb_interface *intf; 562 | __u32 quirks; 563 | int intfnum; 564 | 565 | enum uvc_device_state state; 566 | struct kref kref; 567 | struct list_head list; 568 | 569 | /* Video control interface */ 570 | __u16 uvc_version; 571 | __u32 clock_frequency; 572 | 573 | struct list_head entities; 574 | 575 | struct uvc_video_device video; 576 | 577 | /* Status Interrupt Endpoint */ 578 | struct usb_host_endpoint *int_ep; 579 | struct urb *int_urb; 580 | __u8 status[16]; 581 | 582 | /* Video Streaming interfaces */ 583 | struct list_head streaming; 584 | }; 585 | 586 | enum uvc_handle_state 587 | { 588 | UVC_HANDLE_PASSIVE = 0, 589 | UVC_HANDLE_ACTIVE = 1, 590 | }; 591 | 592 | struct uvc_fh 593 | { 594 | struct uvc_video_device *device; 595 | enum uvc_handle_state state; 596 | }; 597 | 598 | struct uvc_driver 599 | { 600 | struct usb_driver driver; 601 | 602 | struct mutex open_mutex; /* protects from open/disconnect race */ 603 | 604 | struct list_head devices; /* struct uvc_device list */ 605 | struct list_head controls; /* struct uvc_control_info list */ 606 | struct mutex ctrl_mutex; /* protects controls and devices lists */ 607 | }; 608 | 609 | /* ------------------------------------------------------------------------ 610 | * Debugging, printing and logging 611 | */ 612 | 613 | #define UVC_TRACE_PROBE (1 << 0) 614 | #define UVC_TRACE_DESCR (1 << 1) 615 | #define UVC_TRACE_CONTROL (1 << 2) 616 | #define UVC_TRACE_FORMAT (1 << 3) 617 | #define UVC_TRACE_CAPTURE (1 << 4) 618 | #define UVC_TRACE_CALLS (1 << 5) 619 | #define UVC_TRACE_IOCTL (1 << 6) 620 | #define UVC_TRACE_FRAME (1 << 7) 621 | 622 | extern unsigned int uvc_trace_param; 623 | 624 | #define uvc_trace(flag, msg...) \ 625 | do { \ 626 | if (uvc_trace_param & flag) \ 627 | printk(KERN_DEBUG "uvcvideo: " msg); \ 628 | } while(0) 629 | 630 | #define uvc_printk(level, msg...) \ 631 | printk(level "uvcvideo: " msg) 632 | 633 | #define UVC_GUID_FORMAT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" 634 | #define UVC_GUID_ARGS(guid) \ 635 | (guid)[3], (guid)[2], (guid)[1], (guid)[0], \ 636 | (guid)[5], (guid)[4], \ 637 | (guid)[7], (guid)[6], \ 638 | (guid)[8], (guid)[9], \ 639 | (guid)[10], (guid)[11], (guid)[12], \ 640 | (guid)[13], (guid)[14], (guid)[15] 641 | 642 | /* -------------------------------------------------------------------------- 643 | * Internal functions. 644 | */ 645 | 646 | /* Core driver */ 647 | extern struct uvc_driver uvc_driver; 648 | extern void uvc_delete(struct kref *kref); 649 | 650 | /* Video buffers queue management. */ 651 | extern void uvc_queue_init(struct uvc_video_queue *queue); 652 | extern int uvc_alloc_buffers(struct uvc_video_queue *queue, 653 | unsigned int nbuffers, unsigned int buflength); 654 | extern int uvc_free_buffers(struct uvc_video_queue *queue); 655 | extern void uvc_query_buffer(struct uvc_buffer *buf, 656 | struct v4l2_buffer *v4l2_buf); 657 | extern int uvc_queue_buffer(struct uvc_video_queue *queue, 658 | struct v4l2_buffer *v4l2_buf); 659 | extern int uvc_dequeue_buffer(struct uvc_video_queue *queue, 660 | struct v4l2_buffer *v4l2_buf, int nonblocking); 661 | extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable); 662 | extern void uvc_queue_cancel(struct uvc_video_queue *queue); 663 | extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, 664 | struct uvc_buffer *buf); 665 | 666 | /* V4L2 interface */ 667 | extern struct file_operations uvc_fops; 668 | 669 | /* Video */ 670 | extern int uvc_video_init(struct uvc_video_device *video); 671 | extern int uvc_video_enable(struct uvc_video_device *video, int enable); 672 | extern int uvc_probe_video(struct uvc_video_device *video, 673 | struct uvc_streaming_control *probe); 674 | extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, 675 | __u8 intfnum, __u8 cs, void *data, __u16 size); 676 | extern int uvc_set_video_ctrl(struct uvc_video_device *video, 677 | struct uvc_streaming_control *ctrl, int probe); 678 | extern int uvc_init_status(struct uvc_device *dev); 679 | 680 | /* Controls */ 681 | extern struct uvc_control *uvc_find_control(struct uvc_video_device *video, 682 | __u32 v4l2_id, struct uvc_control_mapping **mapping); 683 | extern int uvc_query_v4l2_ctrl(struct uvc_video_device *video, 684 | struct v4l2_queryctrl *v4l2_ctrl); 685 | 686 | extern void uvc_ctrl_add_info(struct uvc_control_info *info); 687 | extern int uvc_ctrl_init_device(struct uvc_device *dev); 688 | extern void uvc_ctrl_cleanup_device(struct uvc_device *dev); 689 | extern void uvc_ctrl_init(void); 690 | 691 | extern int uvc_ctrl_begin(struct uvc_video_device *video); 692 | extern int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback); 693 | static inline int uvc_ctrl_commit(struct uvc_video_device *video) 694 | { 695 | return __uvc_ctrl_commit(video, 0); 696 | } 697 | static inline int uvc_ctrl_rollback(struct uvc_video_device *video) 698 | { 699 | return __uvc_ctrl_commit(video, 1); 700 | } 701 | 702 | extern int uvc_ctrl_get(struct uvc_video_device *video, 703 | struct v4l2_ext_control *xctrl); 704 | extern int uvc_ctrl_set(struct uvc_video_device *video, 705 | struct v4l2_ext_control *xctrl); 706 | 707 | /* Utility functions */ 708 | extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, 709 | unsigned int n_terms, unsigned int threshold); 710 | extern uint32_t uvc_fraction_to_interval(uint32_t numerator, 711 | uint32_t denominator); 712 | extern struct usb_host_endpoint *uvc_find_endpoint( 713 | struct usb_host_interface *alts, __u8 epaddr); 714 | 715 | #endif /* __KERNEL__ */ 716 | 717 | #endif 718 | 719 | -------------------------------------------------------------------------------- /vpx_network.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #ifndef __vpx_NETWORK_H__ 12 | #define __vpx_NETWORK_H__ 13 | 14 | /* vpx_network version info */ 15 | #define vpx_network_version "2.1.1.7" 16 | 17 | #define vpx_NETWORK_VERSION_CHIEF 2 18 | #define vpx_NETWORK_VERSION_MAJOR 1 19 | #define vpx_NETWORK_VERSION_MINOR 1 20 | #define vpx_NETWORK_VERSION_PATCH 7 21 | /* end - vpx_network version info */ 22 | 23 | #include "tctypes.h" 24 | 25 | #if defined(_WIN32_WCE) && _WIN32_WCE < 420 26 | # define WIN32_LEAN_AND_MEAN 27 | # include 28 | # ifndef WINSOCK_VERSION 29 | # define WINSOCK_VERSION MAKEWORD(1,1) 30 | # endif 31 | #elif defined(WIN32) || defined(_WIN32_WCE) 32 | # define WIN32_LEAN_AND_MEAN 33 | # include 34 | # include //for IPv6 structures/functions, IPPROTO_IP options 35 | # ifdef getaddrinfo //some IPv6 calls/structures are missing without the 36 | 37 | //current platform sdk (2/2003) 38 | # define vpx_NET_SUPPORT_IPV6 1 //support on 2000 is an option, but no production 39 | //release will be made for it. If the support isn't 40 | //there the calls will map to IPv4 calls (i.e. getaddrinfo 41 | //to inet_addr/gethostbyname). 42 | //Starting with XP full support was added. 43 | //XP SP.1+/Server 2003 have a production 44 | //implementation of IPv6. 45 | # endif 46 | #elif defined(LINUX) || defined(__uClinux__) || defined(__SYMBIAN32__) 47 | # include //for close if undefined elsewhere 48 | # include 49 | # include //for timeval if undefined elsewhere 50 | # include //for ioctl, FIONREAD 51 | # include //for socket(), bind()...SOCK_STREAM 52 | # include //sockaddr_in... 53 | # include //inet_addr 54 | # include //for addrinfo 55 | # include 56 | #elif defined(VXWORKS) 57 | # include 58 | # include 59 | # include //for sockaddr_in, socket options, etc. 60 | # include //for FIONREAD 61 | # include 62 | #elif defined(TI_OMAP) 63 | # define ntohl(x) htonl(x) 64 | # define ntohs(x) htons(x) 65 | #elif defined(vpx_NET_STUBS) 66 | #else 67 | # error "Network support not yet added for this platform!" 68 | #endif 69 | 70 | #ifndef vpx_NET_SUPPORT_IPV6 71 | # define vpx_NET_SUPPORT_IPV6 0 72 | #endif 73 | 74 | #define vpx_NET_NO_TIMEOUT 0xffffffff 75 | 76 | #if defined(__cplusplus) 77 | extern "C" { 78 | #endif 79 | 80 | #if !defined(vpx_NET_STUBS) 81 | 82 | /* 83 | Valid network layers to be passed to vpx_net_ functions. 84 | Prefixed with vpx_ to prevent naming conflicts. 85 | */ 86 | enum network_layer { 87 | vpx_IPv4, 88 | vpx_IPv6 89 | }; 90 | 91 | /* 92 | Valid transport layers to be passed to vpx_net_ functions. 93 | Prefixed with vpx_ to prevent naming conflicts. 94 | */ 95 | enum transport_layer 96 | { 97 | vpx_TCP = SOCK_STREAM, 98 | vpx_UDP = SOCK_DGRAM 99 | }; 100 | 101 | /* 102 | Union used in calls to vpx_net_ functions. 103 | Depending on the network layer in use the correct sockaddr structure 104 | will be chosen internally by the library. 105 | */ 106 | union vpx_sockaddr_x 107 | { 108 | struct sockaddr_in sa_in; 109 | #if vpx_NET_SUPPORT_IPV6 110 | struct sockaddr_in6 sa_in6; 111 | #endif 112 | }; 113 | 114 | /* 115 | vpx_network's socket representation, used in vpx_net_ function calls 116 | */ 117 | struct vpxsocket 118 | { 119 | 120 | #if defined(WIN32) || defined(_WIN32_WCE) 121 | SOCKET sock; 122 | #else 123 | tc32 sock; 124 | #endif 125 | 126 | tc32 state; 127 | tcu32 read_timeout_ms, 128 | send_timeout_ms; 129 | 130 | enum network_layer nl; 131 | enum transport_layer tl; 132 | 133 | union vpx_sockaddr_x local_addr, 134 | remote_addr; 135 | }; 136 | 137 | /* 138 | vpx_net_init() 139 | Performs any necessary system dependent network initialization. 140 | Should be called before any other vpx_network function. 141 | Return: TC_OK on success, TC_ERROR otherwise 142 | */ 143 | TCRV vpx_net_init(); 144 | 145 | /* 146 | vpx_net_destroy() 147 | Performs any necessary system dependent network deinitialization 148 | */ 149 | void vpx_net_destroy(); 150 | 151 | /* 152 | vpx_net_set_loglevel 153 | Sets the log level for this library 154 | */ 155 | void vpx_net_set_loglevel(tc32 level); 156 | 157 | 158 | /* 159 | vpx_net_open(struct vpxsocket* vpx_sock, enum network_layer net_layer, 160 | enum transport_layer trans_layer) 161 | vpx_sock - pointer to an vpxsocket structure that is to hold network info 162 | net_layer - network layer of the socket to be created 163 | trans_layer - transport layer of the socket to be created 164 | Attempts to create a socket with the specified network 165 | and transport layer. Read and send timeouts default to vpx_NET_NO_TIMEOUT. 166 | Return: 167 | TC_OK: on success 168 | TC_INVALID_PARAMS: if vpx_sock is NULL or if the network/transport 169 | layer is not supported. 170 | TC_ERROR: if a socket could not be created. 171 | */ 172 | TCRV vpx_net_open(struct vpxsocket *vpx_sock, 173 | enum network_layer net_layer, 174 | enum transport_layer trans_layer); 175 | 176 | /* 177 | vpx_net_close(struct vpxsocket* vpx_sock) 178 | vpx_sock - pointer to an vpxsocket structure which 179 | holds the socket to be closed 180 | Attempts to close the socket associated with the vpx_sock structure 181 | Return: 182 | TC_OK: on success 183 | TC_INVALID_PARAMS: if vpx_sock is NULL 184 | TC_ERROR: if the socket could not be closed 185 | */ 186 | TCRV vpx_net_close(struct vpxsocket *vpx_sock); 187 | 188 | /* 189 | vpx_net_bind(struct vpxsocket* vpx_sock, 190 | union vpx_sockaddr_x* vpx_sa_x, 191 | tcu16 port) 192 | vpx_sock - pointer to an vpxsocket structure that contains 193 | the socket to be bound 194 | vpx_sa_x - pointer to an vpx_sockaddr_x struct that contains the 195 | interface to bind to or NULL if the user wants to 196 | bind to any interface. 197 | port - the port to bind the socket to 198 | Attempts to bind vpx_sock to port on the interface specified in vpx_sa_x 199 | or to any interface if vpx_sa_x is NULL. If provided vpx_sa_x should have 200 | been filled out by vpx_net_get_addr_info. 201 | Return: 202 | TC_OK: on success 203 | TC_INVALID_PARAMS: if vpx_sock is NULL or does not point to a structure 204 | that was initialized via vpx_net_open 205 | TC_ERROR: if vpx_sock could not be bound to the specified port 206 | and interface 207 | */ 208 | TCRV vpx_net_bind(struct vpxsocket *vpx_sock, 209 | union vpx_sockaddr_x *vpx_sa_x, 210 | tcu16 port); 211 | 212 | /* 213 | vpx_net_listen(struct vpxsocket* vpx_sock, tc32 backlog) 214 | vpx_sock - pointer to a properly initialized and bound vpxsocket 215 | structure to be setup to listen for incoming connections 216 | backlog - the maximum length the queue of pending connections can grow to. 217 | If the value is less than 1, backlog will be set to the system's 218 | maximum value. 219 | Attempts to put vpx_sock into a state where it can accept incoming connections. 220 | Return: 221 | TC_OK: on success 222 | TC_INVALID_PARAMS: if vpx_sock is NULL, not properly initialized and bound, 223 | or if the transport layer does not support listening 224 | TC_ERROR: if the vpx_sock could not be put into the listening state 225 | */ 226 | TCRV vpx_net_listen(struct vpxsocket *vpx_sock, tc32 backlog); 227 | 228 | /* 229 | vpx_net_accept(struct vpxsocket* vpx_sock, struct vpxsocket* vpx_sock_peer) 230 | vpx_sock - pointer to a properly initialized, bound and listening 231 | vpxsocket structure 232 | vpx_sock_peer - result parameter; pointer to an vpxsocket structure that 233 | will be filled out with the accepted connection's info 234 | Attempts to have vpx_sock accept connections on the port it's currently 235 | listening. If successful, vpx_sock_peer will be filled out with the 236 | remote peer's info. 237 | Return: 238 | TC_OK: on success 239 | TC_INVALID_PARAMS: if vpx_sock is NULL, was not put into the listening 240 | state via vpx_net_listen or vpx_sock_peer is NULL 241 | TC_ERROR: if there was an error accepting connections on vpx_sock 242 | */ 243 | TCRV vpx_net_accept(struct vpxsocket *vpx_sock, struct vpxsocket *vpx_sock_peer); 244 | 245 | /* 246 | vpx_net_connect(struct vpxsocket* vpx_sock, tc8* ip_addr, tcu16 port) 247 | vpx_sock - pointer to an vpxsocket structure that is to be connencted 248 | to the endpoint described by ip_addr and port 249 | ip_addr - pointer to a character string that contains the address to 250 | attempt to connect to 251 | port - the port to attempt to connect to on ip_addr 252 | Attempt to connect vpx_sock to port on ip_addr. 253 | Return: 254 | TC_OK: on success 255 | TC_INVALID_PARAMS: if vpx_sock is NULL, not properly initialized or 256 | if ip_addr is NULL 257 | TC_ERROR: if information could not be obtained about the host or 258 | if a connection could not be established 259 | */ 260 | TCRV vpx_net_connect(struct vpxsocket *vpx_sock, 261 | tc8 *ip_addr, 262 | tcu16 port); 263 | 264 | /* 265 | vpx_net_get_addr_info(tc8* ip_addr, 266 | tcu16 port, 267 | enum network_layer net_layer, 268 | enum transport_layer trans_layer, 269 | union vpx_sockaddr_x* vpx_sa_x) 270 | ip_addr - address to resolve 271 | port - port on ip_addr to obtain information for or 0 indicating any 272 | net_layer - network layer desired on the host machine 273 | trans_layer - the transport layer desired on the host machine 274 | vpx_sa_x - pointer to an vpx_sockaddr_x union that will receive host 275 | information if obtained 276 | Attempts to acquire information about ip_addr that can be used in a 277 | connection attempt. This information will be stored in vpx_sa_x which 278 | can be used in subsequent vpx_net_ functions 279 | Return: 280 | TC_OK: on success 281 | TC_INVALID_PARAMS: if ip_addr or vpx_sa_x are NULL or if the specified 282 | network/transport layers are unsupported by this library 283 | TC_ERROR: if no information could be obtained about the host 284 | */ 285 | TCRV vpx_net_get_addr_info(tc8 *ip_addr, 286 | tcu16 port, 287 | enum network_layer net_layer, 288 | enum transport_layer trans_layer, 289 | union vpx_sockaddr_x *vpx_sa_x); 290 | 291 | /* 292 | vpx_net_read(struct vpxsocket* vpx_sock, tc8* buffer, 293 | tc32 buf_len, tc32* bytes_read) 294 | vpx_sock - pointer to a properly initialized vpxsocket structure 295 | buffer - pointer to a character array where data is to be stored 296 | buf_len - the max max amount of data to be read into buffer 297 | bytes_read - pointer to an integer that will receive the actual amount 298 | of data read or NULL 299 | Attempts to read at most buf_len bytes off the socket into buffer. This 300 | operation can only be done on a connected socket. If a read timeout has 301 | been set to a non-zero value the operation will fail if it could not be 302 | completed within the specified time. If the read timeout has been set to 303 | 0 the operation will fail if it could not be completed immediately. 304 | Return: 305 | TC_OK: on success 306 | TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized 307 | via vpx_net_open, was not connected via 308 | vpx_net_connect, buffer is NULL or buf_len is <= 0 309 | TC_TIMEDOUT: if a read timeout has been set to non-zero value and the 310 | operation could not be completed in the specified time 311 | TC_WOULDBLOCK: if the read timeout has been set to 0 and the operation 312 | could not be completed immediately 313 | TC_ERROR: if an error other than timed out or would block is encountered 314 | trying to complete the operation, more information can be 315 | obtained through calling vpx_net_get_error 316 | */ 317 | TCRV vpx_net_read(struct vpxsocket *vpx_sock, tc8 *buffer, 318 | tc32 buf_len, tc32 *bytes_read); 319 | 320 | /* 321 | vpx_net_recvfrom(struct vpxsocket* vpx_sock, tc8* buffer, tc32 buf_len, 322 | tc32* bytes_read, union vpx_sockaddr_x* vpx_sa_x) 323 | vpx_sock - pointer to a properly initialized vpxsocket structure 324 | buffer - pointer to a character array where data is to be stored 325 | buf_len - max amount of data to be read 326 | bytes_read - pointer to an integer that will receive the actual amount 327 | of data read or NULL 328 | vpx_sa_from - pointer to a vpx_sockaddr_x union used to store the address 329 | of the remote peer the data was received from or NULL 330 | Attempts to read at most buf_len bytes off the socket into buffer. This 331 | operation can be done on a connected or unconnected socket. If a 332 | read timeout has been set to a non-zero value the operation will fail if 333 | it could not be completed within the specified time. If the send timeout 334 | has been set to 0 the operation will fail if it could not be completed 335 | immediately. If data is received and vpx_sa_from is non-NULL the address 336 | of the sender will be stored in it. 337 | Return: 338 | TC_OK: on success 339 | TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized 340 | via vpx_net_open, buffer is NULL or buf_len is <= 0 341 | TC_TIMEDOUT: if a read timeout has been set to non-zero value and the 342 | operation could not be completed in the specified time 343 | TC_WOULDBLOCK: if the read timeout has been set to 0 and the operation 344 | could not be completed immediately 345 | TC_ERROR: if an error other than timed out or would block is encountered 346 | trying to complete the operation, more information can be 347 | obtained through calling vpx_net_get_error 348 | */ 349 | TCRV vpx_net_recvfrom(struct vpxsocket *vpx_sock, tc8 *buffer, tc32 buf_len, 350 | tc32 *bytes_read, union vpx_sockaddr_x *vpx_sa_from); 351 | 352 | /* 353 | vpx_net_send(struct vpxsocket* vpx_sock, tc8* buffer, 354 | tc32 buf_len, tc32* bytes_sent) 355 | vpx_sock - pointer to a properly initialized vpxsocket structure 356 | buffer - pointer to a character array containing data to be sent 357 | buf_len - the length of the data in buffer 358 | bytes_sent - pointer to an integer that will receive the actual amount 359 | of data sent or NULL 360 | Attempts to send buffer to vpx_sock's connected peer. If a send timeout 361 | has been set to a non-zero value the operation will fail if it could not 362 | be completed within the specified time. If the send timeout has been set 363 | to 0 the operation will fail if it could not be completed immediately. 364 | Return: 365 | TC_OK: on success 366 | TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized 367 | via vpx_net_open, was not connected via 368 | vpx_net_connect, buffer is NULL or buf_len is <= 0 369 | TC_TIMEDOUT: if a send timeout has been set to non-zero value and the 370 | operation could not be completed in the specified time 371 | TC_WOULDBLOCK: if the send timeout has been set to 0 and the operation 372 | could not be completed immediately 373 | TC_ERROR: if an error other than timed out or would block is encountered 374 | trying to complete the operation, more information can be 375 | obtained through calling vpx_net_get_error 376 | */ 377 | TCRV vpx_net_send(struct vpxsocket *vpx_sock, tc8 *buffer, 378 | tc32 buf_len, tc32 *bytes_sent); 379 | 380 | /* 381 | vpx_net_sendto(struct vpxsocket* vpx_sock, tc8* buffer, tc32 buf_len, 382 | tc32* bytes_sent, union vpx_sockaddr_x vpx_sa_to) 383 | vpx_sock - pointer to a properly initialized vpxsocket structure 384 | buffer - pointer to a character array containing data to be sent 385 | buf_len - the length of the data in buffer 386 | bytes_sent - pointer to an integer that will receive the actual amount 387 | of data sent or NULL 388 | vpx_sa_to - vpx_sockaddr_x containing the address of the target 389 | Attempts to send buffer to vpx_sockaddr_to. This operation can be done on 390 | connected and unconnected sockets. If a send timeout has been set 391 | to a non-zero value the operation will fail if it could not be completed 392 | within the specified time. If the send timeout has been set to 0 the 393 | operation will fail if it could not be completed immediately. 394 | Return: 395 | TC_OK: on success 396 | TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized 397 | via vpx_net_open, buffer is NULL or buf_len is <= 0 398 | TC_TIMEDOUT: if a send timeout has been set to non-zero value and the 399 | operation could not be completed in the specified time 400 | TC_WOULDBLOCK: if the send timeout has been set to 0 and the operation 401 | could not be completed immediately 402 | TC_ERROR: if an error other than timed out or would block is encountered 403 | trying to complete the operation, more information can be 404 | obtained through calling vpx_net_get_error 405 | */ 406 | TCRV vpx_net_sendto(struct vpxsocket *vpx_sock, tc8 *buffer, tc32 buf_len, 407 | tc32 *bytes_sent, union vpx_sockaddr_x vpx_sa_to); 408 | 409 | /* 410 | vpx_net_is_readable(struct vpxsocket* vpx_sock) 411 | vpx_sock - pointer to a properly initialized vpxsocket structure to 412 | be polled to see if data can be read from it 413 | Return: 414 | 0: vpx_sock was NULL, did not point to a vpxsocket structure that was 415 | initialized via vpx_net_open or the socket has no data that can be read 416 | 1: the socket has data that can be read 417 | */ 418 | tc32 vpx_net_is_readable(struct vpxsocket *vpx_sock); 419 | 420 | /* 421 | vpx_net_amount_readable(struct vpxsocket* vpx_sock, TCRV* rv) 422 | vpx_sock - pointer to a properly initialized vpxsocket structure to 423 | be polled to see if data can be read from it 424 | rv - TCRV pointer to receive the result of the function. This parameter 425 | may be NULL. rv will be set to TC_OK on success and TC_ERROR 426 | on error. 427 | Return: 428 | The amount of data in bytes able to be read off the socket 429 | */ 430 | tc32 vpx_net_amount_readable(struct vpxsocket *vpx_sock, TCRV *rv); 431 | 432 | /* 433 | vpx_net_is_writeable(struct vpxsocket* vpx_sock) 434 | vpx_sock - pointer to a properly initialized vpxsocket structure to 435 | be polled to see if data can be written to it 436 | Return: 437 | 0: vpx_sock was NULL, did not point to a vpxsocket structure that was 438 | initialized via vpx_net_open or the socket cannot be written to 439 | without blocking 440 | 1: the socket can be written to without blocking 441 | */ 442 | tc32 vpx_net_is_writeable(struct vpxsocket *vpx_sock); 443 | 444 | /* 445 | vpx_net_set_read_timeout(struct vpxsocket* vpx_sock, tcu32 read_timeout) 446 | vpx_sock - pointer to a properly initialized vpxsocket structure 447 | read_timeout - time to wait in milliseconds before giving up on a read 448 | operation. 0 indicates that a non-blocking attempt to read 449 | should be made. vpx_NET_NO_TIMEOUT - indicates the socket 450 | should never timeout. 451 | Return: 452 | TC_OK: on success 453 | TC_INVALID_PARAMS: if vpx_sock was NULL or did not point to an vpxsocket 454 | that was initialized via vpx_net_open 455 | */ 456 | TCRV vpx_net_set_read_timeout(struct vpxsocket *vpx_sock, tcu32 read_timeout); 457 | 458 | /* 459 | vpx_net_set_send_timeout(struct vpxsocket* vpx_sock, tcu32 send_timeout) 460 | vpx_sock - pointer to a properly initialized vpxsocket structure 461 | read_timeout - time to wait in milliseconds before giving up on a send 462 | operation. 0 indicates that a non-blocking attempt to send 463 | should be made. vpx_NET_NO_TIMEOUT - indicates the socket 464 | should never timeout. 465 | Return: 466 | TC_OK: on success 467 | TC_INVALID_PARAMS: if vpx_sock was NULL or did not point to an vpxsocket 468 | that was initialized via vpx_net_open 469 | */ 470 | TCRV vpx_net_set_send_timeout(struct vpxsocket *vpx_sock, tcu32 send_timeout); 471 | 472 | /* 473 | vpx_net_get_error(tc32* vpx_net_errno) 474 | vpx_net_errno - pointer to a tc32 to store the last system network 475 | error code or NULL if the user does not want it 476 | Return: 477 | A string representing the last system network error that occurred. This 478 | string can only be used until the next call to vpx_net_get_error() 479 | */ 480 | tc8 *vpx_net_get_error(tc32 *vpx_net_errno); 481 | 482 | /* 483 | vpx_net_recv_buf(struct vpxsocket* vpx_sock, tc8 set, tc32* value) 484 | vpx_sock - a pointer to a properly initialized vpxsocket structure 485 | set - Value indicating whether the option should be set or queried. 486 | 1 indicates the option should be set using the value stored 487 | in value. 0 indicates the current value of the option should 488 | be returned in value. 489 | value - depending on the value of set, either contains the size 490 | to set the socket's receive buffer to or will receive the 491 | current size of the socket's receive buffer 492 | Return: 493 | TC_OK: on success 494 | TC_INVALID_PARAMS: if vpx_sock is NULL, wasn't initialized via 495 | vpx_net_open or value is NULL 496 | TC_ERROR: if the option could not be queried/set 497 | */ 498 | TCRV vpx_net_recv_buf(struct vpxsocket *vpx_sock, tc8 set, tc32 *value); 499 | 500 | /* 501 | vpx_net_send_buf(struct vpxsocket* vpx_sock, tc8 set, tc32* value) 502 | vpx_sock - a pointer to a properly initialized vpxsocket structure 503 | set - Value indicating whether the option should be set or queried. 504 | 1 indicates the option should be set using the value stored 505 | in value. 0 indicates the current value of the option should 506 | be returned in value. 507 | value - depending on the value of set, either contains the size 508 | to set the socket's send buffer to or will receive the 509 | current size of the socket's send buffer 510 | Return: 511 | TC_OK: on success 512 | TC_INVALID_PARAMS: if vpx_sock is NULL, wasn't initialized via 513 | vpx_net_open or value is NULL 514 | TC_ERROR: if the option could not be queried/set 515 | */ 516 | TCRV vpx_net_send_buf(struct vpxsocket *vpx_sock, tc8 set, tc32 *value); 517 | 518 | /* 519 | vpx_net_reuse_addr(struct vpxsocket* vpx_sock, tc8 set, tc32* value) 520 | vpx_sock - a pointer to a properly initialized vpxsocket structure 521 | set - Value indicating whether the option should be set or queried. 522 | 1 indicates the option should be set using the value stored 523 | in value. 0 indicates the current value of the option should 524 | be returned in value. 525 | value - depending on the value of set, either contains an integer 526 | 0/1 to indicate whether the socket's reuse address option 527 | should be turned on or off or will receive the current setting 528 | Return: 529 | TC_OK: on success 530 | TC_INVALID_PARAMS: if vpx_sock is NULL, wasn't initialized via 531 | vpx_net_open or value is NULL 532 | TC_ERROR: if the option could not be queried/set 533 | */ 534 | TCRV vpx_net_reuse_addr(struct vpxsocket *vpx_sock, tc8 set, tc32 *value); 535 | 536 | /* 537 | vpx_net_linger(struct vpxsocket* vpx_sock, tc8 set, tcu16* on, tcu16* sec) 538 | vpx_sock - a pointer to a properly initialized vpxsocket structure 539 | set - Value indicating whether the option should be set or queried. 540 | 1 indicates the option should be set using the values stored in 541 | on and sec. 0 indicates the current value of the option should 542 | be returned in on and sec. 543 | on - depending on the value of set indicates whether to turn on/off (1/0) 544 | the linger option or will receive the current setting 545 | sec - depending on the value of set indicates the amount of time in 546 | seconds for the socket to linger or will receive the current value 547 | Return: 548 | TC_OK: on success 549 | TC_INVALID_PARAMS: if vpx_sock is NULL, wasn't initialized via 550 | vpx_net_open or on or sec are NULL 551 | TC_ERROR: if the option could not be queried/set 552 | */ 553 | TCRV vpx_net_linger(struct vpxsocket *vpx_sock, tc8 set, tcu16 *on, tcu16 *sec); 554 | 555 | /* 556 | vpx_net_multicast_ttl(struct vpxsocket* vpx_sock, tc8 set, tcu8* value) 557 | vpx_sock - pointer to a properly initialized vpxsocket structure 558 | set - flag indicating whether to set (non-zero value) or 559 | query (0) the option 560 | value - depending on the value of set, sets the ttl to the value stored 561 | in value or receives the current value of ttl 562 | Attempts to set/query the multicast ttl value of the socket 563 | represented by vpx_sock 564 | Return: 565 | TC_OK: on success 566 | TC_INVALID_PARAMS: if vpx_sock is NULL, was not initialized via 567 | vpx_net_open, the socket is not a udp socket or 568 | value is NULL 569 | TC_ERROR: if the option could not be queried/set 570 | */ 571 | TCRV vpx_net_multicast_ttl(struct vpxsocket *vpx_sock, tc8 set, tcu8 *value); 572 | 573 | 574 | /* 575 | vpx_net_join_multicast(struct vpxsocket* vpx_sock, 576 | union vpx_sockaddr_x* remote_addr) 577 | vpx_sock - pointer to a properly initialized vpxsocket structure 578 | local_addr - an vpx_sockaddr_x structure containing the address of the 579 | local interface to use for the multicast session or NULL 580 | indicating any interface can be used. (Currently ignored 581 | for IPv6). 582 | remote_addr - an vpx_sockaddr_x structure containing the multicast address 583 | Attempts to add vpx_sock to the multicast session indicated by remote_addr. 584 | On success the reuse_addr option will be set on vpx_sock so others may 585 | join the session and vpx_sock will be added to the session. 586 | Return: 587 | TC_OK: on success 588 | TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized via 589 | vpx_net_open, vpx_sock does not represent a UDP socket, 590 | or remote_addr is NULL 591 | TC_ERROR: if the reuse_addr option could not be set or the socket could 592 | not be added to the multicast session 593 | */ 594 | TCRV vpx_net_join_multicast(struct vpxsocket *vpx_sock, 595 | union vpx_sockaddr_x *local_addr, 596 | union vpx_sockaddr_x *remote_addr); 597 | 598 | /* 599 | vpx_net_join_multicast_addr(struct vpxsocket* vpx_sock 600 | , tc8* ip_addr 601 | , tcu16 port) 602 | vpx_sock - pointer to an vpxsocket structure that is to be connencted 603 | to the endpoint described by ip_addr and port 604 | ip_addr - pointer to a character string that contains the multicast 605 | address to attempt to join 606 | port - the port to attempt to join on ip_addr 607 | Attempt to join vpx_sock to port on ip_addr. 608 | Return: 609 | TC_OK: on success 610 | TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized via 611 | vpx_net_open, vpx_sock does not represent a UDP socket, 612 | or remote_addr is NULL 613 | TC_ERROR: if the reuse_addr option could not be set or the socket could 614 | not be added to the multicast session 615 | */ 616 | TCRV vpx_net_join_multicast_addr(struct vpxsocket *vpx_sock 617 | , tc8 *ip_addr 618 | , tcu16 port); 619 | 620 | 621 | /* 622 | vpx_net_leave_multicast(struct vpxsocket* vpx_sock) 623 | vpx_sock - pointer to a properly initialized vpxsocket structure to be 624 | removed from the multicast session 625 | Attempts to remove vpx_sock from the multicast session it was previously 626 | added to via vpx_net_join_multicast 627 | Return: 628 | TC_OK: on success 629 | TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized via 630 | vpx_net_open or the socket is not a UDP socket 631 | TC_ERROR: if the socket could not be removed from the session 632 | */ 633 | TCRV vpx_net_leave_multicast(struct vpxsocket *vpx_sock); 634 | 635 | #else //!defined(vpx_NET_STUBS) 636 | struct vpxsocket 637 | { 638 | int dummy; 639 | }; 640 | 641 | # define vpx_net_init() 0 642 | # define vpx_net_destroy() 0 643 | # define vpx_net_set_loglevel(l) 644 | tc8 *vpx_net_get_error(tc32 *vpx_net_errno); 645 | 646 | #endif 647 | 648 | #if defined(__cplusplus) 649 | } 650 | #endif 651 | 652 | #endif //__vpx_NETWORK_H__ 653 | -------------------------------------------------------------------------------- /grabcompressandsend.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | /* 12 | * This example illustrates using VP8 in a packet loss scenario by xmitting 13 | * video over UDP with Forward Error Correction, Packet Resend, and 14 | * some Unique VP8 functionality. 15 | * 16 | */ 17 | 18 | #include "vpx_network.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include //for tolower 24 | #include 25 | 26 | extern "C" { 27 | #include "rtp.h" 28 | #define VPX_CODEC_DISABLE_COMPAT 1 29 | #include "vpx/vpx_encoder.h" 30 | #include "vpx/vp8cx.h" 31 | } 32 | 33 | unsigned int drop_first = 10; 34 | unsigned int count_captured_frames = 0; 35 | 36 | const int size_buffer = 1680; 37 | 38 | #define SSRC 411 39 | #define FAIL_ON_NONZERO(x) if((x)) { vpxlog_dbg(ERRORS,#x"\n");return -1; }; 40 | #define FAIL_ON_ZERO(x) if(!(x)) { vpxlog_dbg(ERRORS,#x"\n");return -1; }; 41 | #define FAIL_ON_NEGATIVE(x) if((x)<0) { vpxlog_dbg(ERRORS,#x"\n");return -1; }; 42 | 43 | #ifdef WINDOWS 44 | #include "stdafx.h" 45 | #include 46 | #include 47 | #include 48 | #include "qedit.h" 49 | #pragma comment(lib, "strmiids.lib") 50 | 51 | #include "tctypes.h" 52 | #include 53 | #include 54 | 55 | GUID MEDIASUBTYPE_I420 = 56 | { 57 | MAKEFOURCC('I', '4', '2', '0'), 58 | 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 59 | }; 60 | 61 | CComPtr graph; 62 | CComPtr capture, null_filter, grabber, video_filter; 63 | CComPtr cap_out_pin, grab_in_pin, grab_out_pin, null_in_pin, null_out_pin; 64 | CComPtr sample_grabber; 65 | CComPtr config; 66 | CComQIPtr control; 67 | CComPtr video_window; 68 | #else 69 | #define Sleep(X) usleep(1000*X) 70 | extern "C" int _kbhit(void); 71 | #endif 72 | 73 | vpx_image_t raw; 74 | bool buffer_has_frame = false; 75 | double buffer_time; 76 | long long last_time_in_nanoseconds = 0; 77 | 78 | CODEC video_codec = VPX_VP9; 79 | int display_width = 640; 80 | int display_height = 480; 81 | int capture_frame_rate = 30; 82 | int video_bitrate = 400; 83 | int fec_numerator = 6; 84 | int fec_denominator = 5; 85 | unsigned short send_port = 1407; 86 | unsigned short recv_port = 1408; 87 | 88 | #define PS 2048 89 | #define PSM (PS-1) 90 | #define MAX_NUMERATOR 16 91 | #define MAX_PACKETS_PER_FRAME 40 92 | typedef enum { 93 | NONE, 94 | XOR, 95 | RS 96 | } FEC_TYPE; 97 | 98 | typedef struct { 99 | unsigned int size; 100 | FEC_TYPE fecType; 101 | unsigned int fec_numerator; 102 | unsigned int fec_denominator; 103 | unsigned int new_fec_denominator; 104 | unsigned int count; 105 | unsigned int add_ptr; 106 | unsigned int send_ptr; 107 | unsigned int max; 108 | unsigned int fec_count; 109 | unsigned short seq; 110 | PACKET packet[PS]; 111 | } PACKETIZER; 112 | 113 | PACKETIZER x; 114 | tc8 one_packet[8000]; 115 | 116 | unsigned char output_video_buffer[1280 * 1024 * 3]; 117 | 118 | #ifdef WINDOWS 119 | HRESULT FindFilter(CLSID cls, IBaseFilter **pp, bool name, 120 | CComVariant &filter) { 121 | HRESULT hr; 122 | CComPtr < ICreateDevEnum > dev_enum; 123 | hr = dev_enum.CoCreateInstance(CLSID_SystemDeviceEnum); 124 | 125 | if (!SUCCEEDED(hr)) 126 | return hr; 127 | 128 | CComPtr < IEnumMoniker > enum_moniker; 129 | hr = dev_enum->CreateClassEnumerator(cls, &enum_moniker, 0); 130 | 131 | if (!SUCCEEDED(hr)) 132 | return hr; 133 | 134 | CComPtr < IMoniker > moniker; 135 | ULONG fetched; 136 | 137 | while (enum_moniker->Next(1, &moniker, &fetched) == S_OK) { 138 | CComPtr < IPropertyBag > iPropBag; 139 | hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, (void **) &iPropBag); 140 | 141 | if (SUCCEEDED(hr)) { 142 | // To retrieve the filter's friendly name, do the following: 143 | CComVariant var_name; 144 | hr = iPropBag->Read(L"FriendlyName", &var_name, 0); 145 | 146 | if (SUCCEEDED(hr)) { 147 | if (!name || var_name == filter) { 148 | // To create an instance of the filter, do the following: 149 | hr = moniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void **) pp); 150 | break; 151 | } 152 | } 153 | } 154 | 155 | moniker = NULL; 156 | } 157 | 158 | return hr; 159 | } 160 | 161 | HRESULT GetFirstPin(IBaseFilter *p, PIN_DIRECTION pd, IPin **pp) { 162 | CComPtr < IEnumPins > enum_moniker; 163 | p->EnumPins(&enum_moniker); 164 | CComPtr < IPin > pin; 165 | 166 | while (enum_moniker && enum_moniker->Next(1, &pin, NULL) == S_OK) { 167 | PIN_INFO pi; 168 | pin->QueryPinInfo(&pi); 169 | 170 | if (pi.dir == pd) { 171 | *pp = pin.Detach(); 172 | return S_OK; 173 | } 174 | 175 | pin = NULL; 176 | } 177 | 178 | return E_FAIL; 179 | } 180 | class CVideoCallback : public ISampleGrabberCB { 181 | public: 182 | FILE *output_file;STDMETHODIMP_(ULONG) AddRef() 183 | { 184 | return 2; 185 | }STDMETHODIMP_(ULONG) Release() 186 | { 187 | return 1; 188 | } 189 | STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { 190 | if (riid == IID_ISampleGrabberCB || riid == IID_IUnknown) { 191 | *ppv = (void *) static_cast(this); 192 | return NOERROR; 193 | } 194 | 195 | return E_NOINTERFACE; 196 | } 197 | CVideoCallback(char *filename, int decimate) { 198 | // output_file=fopen(filename,"wb"); 199 | } 200 | ~CVideoCallback() { 201 | // fclose(output_file); 202 | } 203 | STDMETHODIMP SampleCB(double sample_time, IMediaSample *sample) { 204 | return S_OK; 205 | } 206 | STDMETHODIMP BufferCB(double sample_time, BYTE *buffer, long buffer_len) { 207 | 208 | buffer_has_frame = false; 209 | memcpy(raw.img_data, buffer, buffer_len); 210 | buffer_has_frame = true; 211 | buffer_time = sample_time; 212 | //fwrite(inputVideoBuffer,buffer_len,sizeof(BYTE),output_file); 213 | return S_OK; 214 | } 215 | }; 216 | CVideoCallback video_callback("demo.yv12", 0); 217 | CComQIPtr video_callback_ptr( 218 | &video_callback); 219 | #define HRE(y) if(FAILED(hr=y)) {vpxlog_dbg(FRAME,#y##":%x\n",hr);return hr;}; 220 | 221 | int start_capture(void) { 222 | HRESULT hr; 223 | 224 | vpxlog_dbg(FRAME, "Creating filters...\n"); 225 | HRE(graph.CoCreateInstance(CLSID_FilterGraph)); 226 | HRE(FindFilter(CLSID_VideoInputDeviceCategory, &capture, false, 227 | CComVariant(L""))); 228 | HRE(CoCreateInstance(CLSID_SampleGrabber, 0, CLSCTX_INPROC_SERVER, 229 | IID_IBaseFilter, reinterpret_cast(&grabber))); 230 | HRE(grabber->QueryInterface(IID_ISampleGrabber, (void ** )&sample_grabber)); 231 | sample_grabber->SetBufferSamples(true); 232 | HRE(CoCreateInstance(CLSID_VideoRenderer, 0, CLSCTX_INPROC_SERVER, 233 | IID_IBaseFilter, 234 | reinterpret_cast(&video_filter))); 235 | HRE(graph->AddFilter(capture, L"Capture")); 236 | HRE(graph->AddFilter(grabber, L"SampleGrabber")); 237 | HRE(graph->AddFilter(video_filter, L"Video Renderer")); 238 | 239 | vpxlog_dbg(FRAME, "Getting pins...\n"); 240 | HRE(GetFirstPin(capture, PINDIR_OUTPUT, &cap_out_pin)); 241 | HRE(grabber->FindPin(L"In", &grab_in_pin)); 242 | HRE(grabber->FindPin(L"Out", &grab_out_pin)); 243 | HRE(video_filter->FindPin(L"In", &null_in_pin)); 244 | 245 | vpxlog_dbg(FRAME, "Connecting pins...\n"); 246 | AM_MEDIA_TYPE pmt; 247 | ZeroMemory(&pmt, sizeof(AM_MEDIA_TYPE)); 248 | pmt.subtype = MEDIASUBTYPE_I420; 249 | pmt.majortype = MEDIATYPE_Video; 250 | pmt.formattype = FORMAT_VideoInfo; 251 | pmt.pbFormat = reinterpret_cast(CoTaskMemAlloc( 252 | sizeof(VIDEOINFOHEADER))); 253 | ZeroMemory(pmt.pbFormat, sizeof(VIDEOINFOHEADER)); 254 | pmt.cbFormat = sizeof(VIDEOINFOHEADER); 255 | pmt.bFixedSizeSamples = 1; 256 | pmt.bTemporalCompression = 0; 257 | 258 | VIDEOINFOHEADER *pVih = reinterpret_cast(pmt.pbFormat); 259 | pVih->bmiHeader.biCompression = mmioFOURCC('I', '4', '2', '0'); 260 | pVih->bmiHeader.biWidth = display_width; 261 | pVih->bmiHeader.biHeight = display_height; 262 | pVih->bmiHeader.biBitCount = 12; 263 | pVih->bmiHeader.biPlanes = 3; 264 | pVih->bmiHeader.biSizeImage = pVih->bmiHeader.biWidth 265 | * pVih->bmiHeader.biHeight * pVih->bmiHeader.biBitCount / 8; 266 | pVih->AvgTimePerFrame = 10000000 / capture_frame_rate; 267 | pVih->rcSource.top = 0; 268 | pVih->rcSource.left = 0; 269 | pVih->rcSource.bottom = display_height; 270 | pVih->rcSource.right = display_width; 271 | pVih->rcTarget.top = 0; 272 | pVih->rcTarget.left = 0; 273 | pVih->rcTarget.bottom = display_height; 274 | pVih->rcTarget.right = display_width; 275 | pmt.lSampleSize = pVih->bmiHeader.biSizeImage; 276 | 277 | HRE(cap_out_pin->QueryInterface(IID_IAMStreamConfig, (void ** )&config)); 278 | HRE(config->SetFormat(&pmt)); 279 | AM_MEDIA_TYPE *amt; 280 | HRE(config->GetFormat(&amt)); 281 | VIDEOINFOHEADER *pVih2 = reinterpret_cast(amt->pbFormat); 282 | 283 | HRE(graph->Connect(cap_out_pin, grab_in_pin)); 284 | HRE(graph->Connect(grab_out_pin, null_in_pin)); 285 | HRE(video_filter->QueryInterface(IID_IVideoWindow, (void ** )&video_window)); 286 | HRE(sample_grabber->SetCallback(video_callback_ptr, 1)); 287 | 288 | vpxlog_dbg(FRAME, "Running graph...\n"); 289 | control = graph; 290 | 291 | HRE(control->Run()); 292 | return 0; 293 | } 294 | 295 | int get_frame(void) { 296 | if (buffer_has_frame) { 297 | buffer_time = get_time() / 1000.000; 298 | return 0; 299 | } else 300 | return -1; 301 | } 302 | #else 303 | 304 | #ifdef MACOSX 305 | 306 | #include 307 | #include 308 | #include 309 | #include 310 | #include 311 | 312 | #include 313 | #include 314 | 315 | #include 316 | 317 | struct my_source_context { 318 | vidcap_src *src; 319 | char name[VIDCAP_NAME_LENGTH]; 320 | }; 321 | 322 | char frame[1280 * 720 * 3 / 2]; 323 | 324 | int get_frame(void) { 325 | if (buffer_has_frame) { 326 | buffer_time = get_time() / 1000.000; 327 | return 0; 328 | } else 329 | return -1; 330 | } 331 | 332 | static int user_capture_callback(vidcap_src *src, void *user_data, 333 | struct vidcap_capture_info *cap_info) { 334 | memcpy(raw.img_data, cap_info->video_data, 335 | display_width * display_height * 3 / 2); 336 | 337 | buffer_has_frame = 1; 338 | 339 | return 0; 340 | } 341 | const int sleep_ms = 10000; 342 | vidcap_state *vc; 343 | vidcap_sapi *sapi; 344 | 345 | struct vidcap_sapi_info sapi_info; 346 | struct vidcap_src_info *src_list; 347 | int src_list_len; 348 | struct my_source_context *ctx_list; 349 | int start_capture(void) { 350 | int i; 351 | 352 | FAIL_ON_ZERO(vc = vidcap_initialize()); 353 | FAIL_ON_ZERO(sapi = vidcap_sapi_acquire(vc, 0)); 354 | 355 | FAIL_ON_NONZERO(vidcap_sapi_info_get(sapi, &sapi_info)); 356 | 357 | src_list_len = vidcap_src_list_update(sapi); 358 | 359 | if (src_list_len < 0) { 360 | vpxlog_dbg(ERRORS, "failed vidcap_src_list_update()\n"); 361 | return -1; 362 | } else if (src_list_len == 0) { 363 | vpxlog_dbg(ERRORS, "no sources available\n"); 364 | return -1; 365 | } 366 | 367 | FAIL_ON_ZERO( 368 | src_list = (struct vidcap_src_info * ) calloc( 369 | src_list_len, sizeof(struct vidcap_src_info))) 370 | 371 | FAIL_ON_NONZERO(vidcap_src_list_get(sapi, src_list_len, src_list)); 372 | FAIL_ON_ZERO( 373 | ctx_list = (my_source_context * ) calloc(src_list_len, sizeof(*ctx_list))) 374 | 375 | for (i = 0; i < src_list_len; ++i) { 376 | struct vidcap_fmt_info fmt_info; 377 | ctx_list[i].src = vidcap_src_acquire(sapi, &src_list[i]); 378 | fmt_info.width = display_width; 379 | fmt_info.height = display_height; 380 | fmt_info.fps_numerator = capture_frame_rate; 381 | fmt_info.fps_denominator = 1; 382 | fmt_info.fourcc = 100; // i420 383 | 384 | FAIL_ON_NONZERO(vidcap_format_bind(ctx_list[i].src, &fmt_info)); 385 | FAIL_ON_NONZERO(vidcap_format_info_get(ctx_list[i].src, &fmt_info)); 386 | 387 | sprintf(ctx_list[i].name, "source %d", i); 388 | 389 | FAIL_ON_NONZERO( 390 | vidcap_src_capture_start(ctx_list[i].src, user_capture_callback, 391 | &ctx_list[i])) 392 | } 393 | 394 | free(src_list); 395 | return 0; 396 | 397 | } 398 | int stop_capture(void) { 399 | int i; 400 | 401 | for (i = 0; i < src_list_len; ++i) { 402 | if (!ctx_list[i].src) 403 | continue; 404 | 405 | FAIL_ON_NONZERO(vidcap_src_capture_stop(ctx_list[i].src)) 406 | FAIL_ON_NONZERO(vidcap_src_release(ctx_list[i].src)) 407 | } 408 | 409 | free(ctx_list); 410 | FAIL_ON_NONZERO(vidcap_sapi_release(sapi)) 411 | 412 | vidcap_destroy(vc); 413 | 414 | return 0; 415 | } 416 | 417 | #else 418 | #include 419 | #include 420 | #include 421 | #include 422 | #include 423 | #include 424 | #include "uvcvideo.h" 425 | #include 426 | #include 427 | #define NB_BUFFER 4 428 | 429 | using namespace std; 430 | char frame[1280 * 720 * 3 / 2]; 431 | 432 | int uyvy2yv12(char *uyvy, int w, int h) { 433 | unsigned char *y = raw.img_data; 434 | unsigned char *u = w * h + y; 435 | unsigned char *v = w / 2 * h / 2 + u; 436 | int i, j; 437 | 438 | char *p = uyvy; 439 | 440 | // pretty clearly a very slow way to do this even in c 441 | // super easy simd conversion 442 | for (; y < u; p += 4) { 443 | *y++ = p[0]; 444 | *y++ = p[2]; 445 | } 446 | 447 | p = uyvy; 448 | 449 | for (i = 0; i < (h >> 1); i++, p += (w << 1)) 450 | for (j = 0; j < (w >> 1); j++, p += 4) 451 | *u++ = p[1]; 452 | 453 | p = uyvy; 454 | 455 | for (i = 0; i < (h >> 1); i++, p += (w << 1)) 456 | for (j = 0; j < (w >> 1); j++, p += 4) 457 | *v++ = p[3]; 458 | 459 | return 0; 460 | } 461 | 462 | struct v4l2_capability cap; 463 | struct v4l2_format fmt; 464 | struct v4l2_buffer buf; 465 | struct v4l2_requestbuffers rb; 466 | void *mem[NB_BUFFER]; 467 | int fd; 468 | int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 469 | 470 | int start_capture(void) { 471 | 472 | FAIL_ON_NEGATIVE(fd = open("/dev/video0", O_RDWR | O_NONBLOCK)) 473 | 474 | memset(&cap, 0, sizeof(struct v4l2_capability)); 475 | 476 | FAIL_ON_NEGATIVE(ioctl(fd, VIDIOC_QUERYCAP, &cap)) 477 | 478 | memset(&fmt, 0, sizeof(struct v4l2_format)); 479 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 480 | fmt.fmt.pix.width = display_width; 481 | fmt.fmt.pix.height = display_height; 482 | fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 483 | fmt.fmt.pix.field = V4L2_FIELD_ANY; 484 | 485 | FAIL_ON_NEGATIVE(ioctl(fd, VIDIOC_S_FMT, &fmt)) 486 | 487 | struct v4l2_streamparm setfps; 488 | 489 | memset(&setfps, 0, sizeof(struct v4l2_streamparm)); 490 | setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 491 | setfps.parm.capture.timeperframe.numerator = 1; 492 | setfps.parm.capture.timeperframe.denominator = capture_frame_rate; 493 | FAIL_ON_NONZERO(ioctl(fd, VIDIOC_S_PARM, &setfps)) 494 | 495 | 496 | memset(&rb, 0, sizeof(struct v4l2_requestbuffers)); 497 | rb.count = NB_BUFFER; 498 | rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 499 | rb.memory = V4L2_MEMORY_MMAP; 500 | 501 | FAIL_ON_NONZERO(ioctl(fd, VIDIOC_REQBUFS, &rb)) 502 | 503 | int i; 504 | 505 | /* map the buffers */ 506 | for (i = 0; i < NB_BUFFER; i++) { 507 | memset(&buf, 0, sizeof(struct v4l2_buffer)); 508 | buf.index = i; 509 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 510 | buf.memory = V4L2_MEMORY_MMAP; 511 | 512 | FAIL_ON_NEGATIVE(ioctl(fd, VIDIOC_QUERYBUF, &buf)) 513 | 514 | mem[i] = mmap(0, buf.length, PROT_READ, MAP_SHARED, fd, buf.m.offset); 515 | 516 | if (mem[i] == MAP_FAILED) { 517 | cout << "Error mapping buffers." << endl; 518 | return -1; 519 | } 520 | } 521 | 522 | /* Queue the buffers. */ 523 | for (i = 0; i < NB_BUFFER; ++i) { 524 | memset(&buf, 0, sizeof(struct v4l2_buffer)); 525 | buf.index = i; 526 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 527 | buf.memory = V4L2_MEMORY_MMAP; 528 | 529 | FAIL_ON_NEGATIVE(ioctl(fd, VIDIOC_QBUF, &buf)) 530 | } 531 | 532 | // start streaming 533 | FAIL_ON_NEGATIVE(ioctl(fd, VIDIOC_STREAMON, &type)) 534 | return -1; 535 | } 536 | 537 | int get_frame(void) { 538 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 539 | buf.memory = V4L2_MEMORY_MMAP; 540 | 541 | // get a frame if we can 542 | if (ioctl(fd, VIDIOC_DQBUF, &buf) < 0) 543 | return -1; 544 | 545 | // super ugly conversion :) 546 | if (buf.bytesused > 0) { 547 | uyvy2yv12((char *) mem[buf.index], display_width, display_height); 548 | //fwrite(frame, w*h*3/2, 1, captureFile); 549 | } 550 | 551 | // put the buffer back 552 | FAIL_ON_NEGATIVE(ioctl(fd, VIDIOC_QBUF, &buf)) 553 | 554 | buffer_time = get_time() / 1000.000; 555 | 556 | if (count_captured_frames++ < drop_first) 557 | return -1; 558 | 559 | return 0; 560 | } 561 | 562 | int stop_capture(void) { 563 | //fclose(captureFile); 564 | FAIL_ON_NEGATIVE(ioctl(fd, VIDIOC_STREAMOFF, &type)) 565 | 566 | return 0; 567 | } 568 | 569 | #endif 570 | #endif 571 | 572 | int create_packetizer(PACKETIZER *x, FEC_TYPE fecType, 573 | unsigned int fec_numerator, 574 | unsigned int fec_denominator) { 575 | x->size = PACKET_SIZE; 576 | x->fecType = fecType; 577 | x->fec_numerator = fec_numerator; 578 | x->fec_denominator = fec_denominator; 579 | x->new_fec_denominator = fec_denominator; 580 | x->max = PS; 581 | x->count = 0; 582 | x->add_ptr = 0; 583 | x->send_ptr = 0; 584 | x->fec_count = x->fec_denominator; 585 | 586 | x->seq = 7; 587 | x->send_ptr = x->add_ptr = (x->seq & PSM); 588 | return 0; // SUCCESS 589 | } 590 | 591 | int make_redundant_packet(PACKETIZER *p, unsigned int end_frame, 592 | unsigned int time, unsigned int frametype) { 593 | long long *in[MAX_NUMERATOR]; 594 | long long *out = (long long *) p->packet[p->add_ptr].data; 595 | unsigned int i, j; 596 | unsigned int max_size = 0; 597 | unsigned int max_round; 598 | 599 | // make a number of exact duplicates of this packet 600 | if (p->fec_denominator == 1) { 601 | int dups = p->fec_numerator - p->fec_denominator; 602 | void *duplicand = (void *) &p->packet[(p->add_ptr - 1) & PSM]; 603 | 604 | while (dups) { 605 | memcpy((void *) &p->packet[p->add_ptr], duplicand, sizeof(PACKET)); 606 | dups--; 607 | p->add_ptr++; 608 | p->add_ptr &= PSM; 609 | } 610 | 611 | p->fec_denominator = p->new_fec_denominator; 612 | p->fec_count = p->fec_denominator; 613 | p->count++; 614 | return 0; 615 | } 616 | 617 | p->packet[p->add_ptr].ssrc = SSRC; 618 | p->packet[p->add_ptr].csrccount = 1; 619 | p->packet[p->add_ptr].csrc = SSRC; 620 | p->packet[p->add_ptr].pad = 0; 621 | p->packet[p->add_ptr].timestamp = R4(time); 622 | p->packet[p->add_ptr].seq = R2(p->seq); 623 | p->packet[p->add_ptr].type = XORPACKET; 624 | p->packet[p->add_ptr].redundant_count = p->fec_denominator; 625 | p->packet[p->add_ptr].new_frame = 0; 626 | p->packet[p->add_ptr].end_frame = end_frame; 627 | p->packet[p->add_ptr].frame_type = frametype; 628 | 629 | // find address of last denominator packets data store in in ptr 630 | for (i = 0; i < p->fec_denominator; i++) { 631 | int ptr = ((p->add_ptr - i - 1) & PSM); 632 | in[i] = (long long *) p->packet[ptr].data; 633 | ; 634 | max_size = 635 | (max_size > p->packet[ptr].size ? max_size : p->packet[ptr].size); 636 | } 637 | 638 | // go through a full packet size 639 | max_round = (max_size + sizeof(long long) - 1) / sizeof(long long); 640 | 641 | for (j = 0; j < max_round; j++) { 642 | // start with the most recent packet 643 | *out = *(in[0]); 644 | 645 | // xor all the older packets with out 646 | for (i = 1; i < p->fec_denominator; i++) { 647 | *out ^= *(in[i]); 648 | in[i]++; 649 | } 650 | 651 | in[0]++; 652 | out++; 653 | } 654 | p->packet[p->add_ptr].size = max_size; 655 | 656 | p->seq++; 657 | 658 | // move to the next packet 659 | p->add_ptr++; 660 | p->add_ptr &= PSM; 661 | 662 | // add one to our packet count 663 | p->count++; 664 | 665 | if (p->count > p->max) 666 | return -1; // filled up our packet buffer 667 | 668 | p->fec_denominator = p->new_fec_denominator; 669 | p->fec_count = p->fec_denominator; 670 | return 0; 671 | } 672 | 673 | int packetize(PACKETIZER *p, unsigned int time, unsigned char *data, 674 | unsigned int size, unsigned int frame_type) { 675 | int new_frame = 1; 676 | 677 | // more bytes to copy around 678 | while (size > 0) { 679 | unsigned int psize = (p->size < size ? p->size : size); 680 | p->packet[p->add_ptr].ssrc = SSRC; 681 | p->packet[p->add_ptr].csrccount = 1; 682 | p->packet[p->add_ptr].csrc = SSRC; 683 | p->packet[p->add_ptr].pad = 0; 684 | p->packet[p->add_ptr].timestamp = R4(time); 685 | p->packet[p->add_ptr].seq = R2(p->seq); 686 | p->packet[p->add_ptr].size = psize; 687 | p->packet[p->add_ptr].type = DATAPACKET; 688 | 689 | if (p->fec_denominator == 1) 690 | p->packet[p->add_ptr].redundant_count = 2; 691 | else 692 | p->packet[p->add_ptr].redundant_count = p->fec_count; 693 | 694 | p->packet[p->add_ptr].new_frame = new_frame; 695 | p->packet[p->add_ptr].frame_type = frame_type; 696 | //vpxlog_dbg(SKIP, "%c", (frame_type==NORMAL?'N':'O')); 697 | 698 | new_frame = 0; 699 | 700 | memcpy(p->packet[p->add_ptr].data, data, psize); 701 | 702 | // make sure rest of packet is 0'ed out for redundancy if necessary. 703 | if (size < p->size) 704 | memset(p->packet[p->add_ptr].data + psize, 0, p->size - psize); 705 | 706 | data += psize; 707 | size -= psize; 708 | p->packet[p->add_ptr].end_frame = (size == 0); 709 | 710 | p->seq++; 711 | p->add_ptr++; 712 | p->add_ptr &= PSM; 713 | 714 | p->count++; 715 | 716 | if (p->count > p->max) 717 | return -1; // filled up our packet buffer 718 | 719 | // time for redundancy? 720 | p->fec_count--; 721 | 722 | if (!p->fec_count) 723 | make_redundant_packet(p, (size == 0), time, frame_type); 724 | } 725 | 726 | return 0; 727 | } 728 | //#define WRITEFILE 729 | //#define ONEWAY 730 | int send_packet(PACKETIZER *p, struct vpxsocket *vpxSock, 731 | union vpx_sockaddr_x address) { 732 | tc32 bytes_sent; 733 | 734 | if (p->send_ptr == p->add_ptr) 735 | return -1; 736 | 737 | vpxlog_dbg(LOG_PACKET, "Sent Packet %d, %u, %d : new=%d %d %x\n", 738 | R2(p->packet[p->send_ptr].seq), 739 | R4(p->packet[p->send_ptr].timestamp), 740 | p->packet[p->send_ptr].frame_type, p->packet[p->send_ptr].size, 741 | p->packet[p->send_ptr].new_frame, address); 742 | 743 | vpx_net_sendto(vpxSock, (tc8 *) &p->packet[p->send_ptr], 744 | PACKET_HEADER_SIZE + p->packet[p->send_ptr].size, &bytes_sent, address); 745 | 746 | p->send_ptr++; 747 | p->send_ptr &= PSM; 748 | p->count--; 749 | 750 | return 0; 751 | } 752 | void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s) { 753 | if (ctx->err) { 754 | vpxlog_dbg(FRAME, "%s: %s\n", s, vpx_codec_error(ctx)); 755 | exit (EXIT_FAILURE); 756 | } 757 | } 758 | 759 | int main(int argc, char *argv[]) { 760 | char ip[512]; 761 | int flags = 0; 762 | strncpy(ip, "127.0.0.1", 512); 763 | printf("GrabCompressAndSend: (-? for help) \n"); 764 | 765 | vpx_codec_enc_cfg_t cfg; 766 | 767 | // Go through the args once to look for codec 768 | for (int arg = 0; arg < argc; arg++) { 769 | if (argv[arg][0] == '-') { 770 | switch (argv[arg][1]) { 771 | case '8': 772 | video_codec = VPX_VP8; 773 | break; 774 | case '9': 775 | video_codec = VPX_VP9; 776 | break; 777 | } 778 | } 779 | } 780 | 781 | if (video_codec == VPX_VP8) { 782 | printf("VP8 \n"); 783 | vpx_codec_enc_config_default(&vpx_codec_vp8_cx_algo, &cfg, 0); 784 | } else { 785 | printf("VP9 \n"); 786 | vpx_codec_enc_config_default(&vpx_codec_vp9_cx_algo, &cfg, 0); 787 | } 788 | 789 | cfg.rc_target_bitrate = video_bitrate; 790 | cfg.g_w = display_width; 791 | cfg.g_h = display_height; 792 | cfg.g_timebase.num = 1; 793 | cfg.g_timebase.den = (int) 10000000; 794 | cfg.rc_end_usage = VPX_CBR; 795 | cfg.g_pass = VPX_RC_ONE_PASS; 796 | cfg.g_lag_in_frames = 0; 797 | cfg.rc_min_quantizer = 20; 798 | cfg.rc_max_quantizer = 50; 799 | cfg.rc_dropframe_thresh = 1; 800 | cfg.rc_buf_optimal_sz = 200; 801 | cfg.rc_buf_initial_sz = 200; 802 | cfg.rc_buf_sz = 200; 803 | cfg.g_error_resilient = 1; 804 | cfg.kf_mode = VPX_KF_DISABLED; 805 | cfg.kf_max_dist = 999999; 806 | cfg.g_threads = 2; 807 | cfg.rc_resize_allowed = 0; 808 | 809 | int cpu_used = 6; 810 | int static_threshold = 1200; 811 | 812 | for (int arg = 0; arg < argc; arg++) { 813 | if (argv[arg][0] == '-') { 814 | switch (argv[arg][1]) { 815 | case 'm': 816 | case 'M': 817 | cfg.rc_dropframe_thresh = atoi(argv[++arg]); 818 | break; 819 | case 'c': 820 | case 'C': 821 | cpu_used = atoi(argv[++arg]); 822 | break; 823 | case 't': 824 | case 'T': 825 | static_threshold = atoi(argv[++arg]); 826 | break; 827 | case 'b': 828 | case 'B': 829 | cfg.rc_min_quantizer = atoi(argv[++arg]); 830 | break; 831 | case 'q': 832 | case 'Q': 833 | cfg.rc_max_quantizer = atoi(argv[++arg]); 834 | break; 835 | case 'd': 836 | case 'D': 837 | drop_first = atoi(argv[++arg]); 838 | break; 839 | case 'i': 840 | case 'I': 841 | strncpy(ip, argv[++arg], 512); 842 | break; 843 | case 's': 844 | case 'S': 845 | send_port = atoi(argv[++arg]); 846 | break; 847 | case 'r': 848 | case 'R': 849 | recv_port = atoi(argv[++arg]); 850 | break; 851 | case '8': 852 | case '9': 853 | break; 854 | default: 855 | printf("========================: \n" 856 | "Captures, compresses and sends video to" 857 | "ReceiveDecompressAndPlay sample\n\n" 858 | "-m [1] buffer level at which to drop frames 0 shuts it off \n" 859 | "-c [12] amount of cpu to leave free of 16 \n" 860 | "-t [1200] sad score below which is just a copy \n" 861 | "-b [20] minimum quantizer ( best frame quality )\n" 862 | "-q [52] maximum frame quantizer ( worst frame quality ) \n" 863 | "-d [60] number of frames to drop at the start\n" 864 | "-i [127.0.0.1] Port to send data to. \n" 865 | "-s [1408] port to send requests to\n" 866 | "-r [1407] port to receive requests on. \n\n"); 867 | exit(0); 868 | break; 869 | } 870 | } 871 | } 872 | 873 | struct vpxsocket vpx_socket, vpx_socket2; 874 | 875 | union vpx_sockaddr_x address, address2; 876 | 877 | TCRV rc; 878 | 879 | int i; 880 | 881 | int bytes_read; 882 | 883 | #ifdef WINDOWS 884 | HRESULT hr; 885 | 886 | HRE(CoInitialize(NULL)); 887 | 888 | #endif 889 | 890 | #ifdef WRITEFILE 891 | FILE *out_file = fopen("test.vpx", "wb"); 892 | 893 | #endif 894 | 895 | int request_recovery = 0; 896 | 897 | int gold_recovery_seq = 0; 898 | 899 | int altref_recovery_seq = 0; 900 | 901 | unsigned int recovery_flags[] = {0, // NORMAL, 902 | VPX_EFLAG_FORCE_KF, // KEY, 903 | VP8_EFLAG_FORCE_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_LAST 904 | | VP8_EFLAG_NO_REF_ARF, // GOLD = 2, 905 | VP8_EFLAG_FORCE_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_REF_LAST 906 | | VP8_EFLAG_NO_REF_GF // ALTREF = 3 907 | }; 908 | 909 | vpx_net_init(); 910 | 911 | // data send socket 912 | FAIL_ON_NONZERO(vpx_net_open(&vpx_socket, vpx_IPv4, vpx_UDP)) 913 | FAIL_ON_NONZERO( 914 | vpx_net_get_addr_info(ip, send_port, vpx_IPv4, vpx_UDP, &address)) 915 | // feedback socket 916 | FAIL_ON_NONZERO(vpx_net_open(&vpx_socket2, vpx_IPv4, vpx_UDP)) 917 | vpx_net_set_read_timeout(&vpx_socket2, 0); 918 | 919 | rc = vpx_net_bind(&vpx_socket2, 0, recv_port); 920 | 921 | vpx_net_set_send_timeout(&vpx_socket, vpx_NET_NO_TIMEOUT); 922 | 923 | // make sure 2 way discussion taking place before getting started 924 | 925 | int bytes_sent; 926 | 927 | #ifndef ONEWAY 928 | char init_packet[PACKET_SIZE] = "initiate call"; 929 | rc = vpx_net_sendto(&vpx_socket, (tc8 *) &init_packet, PACKET_SIZE, 930 | &bytes_sent, address); 931 | 932 | while (!_kbhit()) { 933 | 934 | rc = vpx_net_recvfrom(&vpx_socket2, one_packet, sizeof(one_packet), 935 | &bytes_read, &address2); 936 | 937 | if (rc != TC_OK && rc != TC_WOULDBLOCK) 938 | vpxlog_dbg(LOG_PACKET, "error\n"); 939 | 940 | if (bytes_read == -1) 941 | bytes_read = 0; 942 | 943 | if (bytes_read) { 944 | if (strncmp(one_packet, "configuration ", 14) == 0) { 945 | sscanf(one_packet + 14, "%d %d %d %d %d %d", &display_width, 946 | &display_height, &capture_frame_rate, &video_bitrate, 947 | &fec_numerator, &fec_denominator); 948 | printf("Dimensions: %dx%-d %dfps %dkbps %d/%dFEC\n", display_width, 949 | display_height, capture_frame_rate, video_bitrate, fec_numerator, 950 | fec_denominator); 951 | break; 952 | } 953 | } else { 954 | rc = vpx_net_sendto(&vpx_socket, (tc8 *) &init_packet, PACKET_SIZE, 955 | &bytes_sent, address); 956 | Sleep(200); 957 | 958 | } 959 | } 960 | 961 | char conf_packet[PACKET_SIZE] = "confirmed"; 962 | rc = vpx_net_sendto(&vpx_socket, (tc8 *) &conf_packet, PACKET_SIZE, 963 | &bytes_sent, address); 964 | Sleep(200); 965 | rc = vpx_net_sendto(&vpx_socket, (tc8 *) &conf_packet, PACKET_SIZE, 966 | &bytes_sent, address); 967 | Sleep(200); 968 | rc = vpx_net_sendto(&vpx_socket, (tc8 *) &conf_packet, PACKET_SIZE, 969 | &bytes_sent, address); 970 | #endif 971 | 972 | vpx_codec_ctx_t encoder; 973 | vpx_img_alloc(&raw, VPX_IMG_FMT_YV12, display_width, display_height, 1); 974 | 975 | cfg.rc_target_bitrate = video_bitrate; 976 | 977 | cfg.g_w = display_width; 978 | cfg.g_h = display_height; 979 | 980 | if (video_codec == VPX_VP8) { 981 | vpx_codec_enc_init(&encoder, &vpx_codec_vp8_cx_algo, &cfg, 0); 982 | vpx_codec_control_(&encoder, VP8E_SET_CPUUSED, cpu_used); 983 | vpx_codec_control_(&encoder, VP8E_SET_STATIC_THRESHOLD, static_threshold); 984 | vpx_codec_control_(&encoder, VP8E_SET_ENABLEAUTOALTREF, 0); 985 | vpx_codec_control_(&encoder, VP8E_SET_NOISE_SENSITIVITY, 2); 986 | } else { 987 | vpx_codec_enc_init(&encoder, &vpx_codec_vp9_cx_algo, &cfg, 0); 988 | vpx_codec_control_(&encoder, VP8E_SET_CPUUSED, cpu_used); 989 | vpx_codec_control_(&encoder, VP8E_SET_STATIC_THRESHOLD, static_threshold); 990 | vpx_codec_control_(&encoder, VP8E_SET_ENABLEAUTOALTREF, 0); 991 | vpx_codec_control_(&encoder, VP9E_SET_AQ_MODE, 3); 992 | vpx_codec_control_(&encoder, VP9E_SET_TILE_COLUMNS, 2); 993 | vpx_codec_control_(&encoder, VP9E_SET_FRAME_PARALLEL_DECODING, 1); 994 | vpx_codec_control_(&encoder, VP8E_SET_ENABLEAUTOALTREF, 0); 995 | vpx_codec_control_(&encoder, VP8E_SET_GF_CBR_BOOST_PCT, 200); 996 | } 997 | create_packetizer(&x, XOR, fec_numerator, fec_denominator); 998 | //HRE(CoInitialize(NULL)); 999 | 1000 | start_capture(); 1001 | vpx_net_set_read_timeout(&vpx_socket2, 1); 1002 | 1003 | for (i = 0; !_kbhit();) { 1004 | 1005 | // if there is nothing to send 1006 | #ifndef ONEWAY 1007 | rc = vpx_net_recvfrom(&vpx_socket2, one_packet, sizeof(one_packet), 1008 | &bytes_read, &address2); 1009 | 1010 | if (rc != TC_OK && rc != TC_WOULDBLOCK && rc != TC_TIMEDOUT) 1011 | vpxlog_dbg(LOG_PACKET, "error\n"); 1012 | 1013 | if (bytes_read == -1) 1014 | bytes_read = 0; 1015 | 1016 | if (bytes_read) { 1017 | unsigned char command = one_packet[0]; 1018 | unsigned short seq = *((unsigned short *) (1 + one_packet)); 1019 | int bytes_sent; 1020 | 1021 | PACKET *tp = &x.packet[seq & PSM]; 1022 | 1023 | // ignore invalid commands 1024 | if (command != 'r' && command != 'g') 1025 | continue; 1026 | 1027 | vpxlog_dbg(SKIP, "Command :%c Seq:%d FT:%c RecoverySeq:%d AltSeq:%d \n", 1028 | command, seq, (tp->frame_type == NORMAL ? 'N' : 'G'), 1029 | gold_recovery_seq, altref_recovery_seq); 1030 | 1031 | // requested resend ( ignore if we are about to send a recovery frame) 1032 | if (command == 'r' && request_recovery == 0) { 1033 | rc = vpx_net_sendto(&vpx_socket, (tc8 *) &x.packet[seq & PSM], 1034 | PACKET_HEADER_SIZE + x.packet[seq & PSM].size, 1035 | &bytes_sent, address); 1036 | vpxlog_dbg(SKIP, "Sent recovery packet %d,%c:%d %d, %d,%d,%u %x\n", rc, 1037 | command, tp->frame_type, seq, R2(tp->seq), R4(tp->timestamp), 1038 | bytes_sent, address); 1039 | continue; 1040 | } 1041 | 1042 | int recovery_seq = gold_recovery_seq; 1043 | int recovery_type = GOLD; 1044 | int other_recovery_seq = altref_recovery_seq; 1045 | int other_recovery_type = ALTREF; 1046 | 1047 | if ((unsigned short) (recovery_seq - altref_recovery_seq > 32768)) { 1048 | recovery_seq = altref_recovery_seq; 1049 | recovery_type = ALTREF; 1050 | other_recovery_seq = gold_recovery_seq; 1051 | other_recovery_type = GOLD; 1052 | } 1053 | 1054 | // if requested to recover but seq is before recovery RESEND 1055 | if ((unsigned short) (seq - recovery_seq) > 32768 || command == 'r') { 1056 | rc = vpx_net_sendto(&vpx_socket, (tc8 *) &x.packet[seq & PSM], 1057 | PACKET_HEADER_SIZE + x.packet[seq & PSM].size, 1058 | &bytes_sent, address); 1059 | vpxlog_dbg(SKIP, "Sent recovery packet %c:%d, %d,%u\n", command, 1060 | tp->frame_type, seq, R4(tp->timestamp)); 1061 | continue; 1062 | } 1063 | 1064 | // requested recovery frame and its a normal frame packet that's 1065 | // lost and seq is after our recovery frame so make a long term ref frame 1066 | if (tp->frame_type == NORMAL && (unsigned short) (seq - recovery_seq) > 0 1067 | && (unsigned short) (seq - recovery_seq) < 32768) { 1068 | request_recovery = recovery_type; 1069 | vpxlog_dbg(SKIP, "Requested recovery frame %c:%c,%d,%u\n", command, 1070 | (recovery_type == GOLD ? 'G' : 'A'), 1071 | x.packet[gold_recovery_seq & PSM].frame_type, seq, 1072 | R4(x.packet[gold_recovery_seq&PSM].timestamp)); 1073 | continue; 1074 | } 1075 | 1076 | // so the other one is too old request a recovery frame from an older 1077 | // reference buffer. 1078 | if ((unsigned short) (seq - other_recovery_seq) > 0 1079 | && (unsigned short) (seq - other_recovery_seq) < 32768) { 1080 | request_recovery = other_recovery_type; 1081 | vpxlog_dbg(SKIP, "Requested recovery frame %c:%c,%d,%u\n", command, 1082 | (other_recovery_type == GOLD ? 'G' : 'A'), 1083 | x.packet[gold_recovery_seq & PSM].frame_type, seq, 1084 | R4(x.packet[gold_recovery_seq&PSM].timestamp)); 1085 | continue; 1086 | } 1087 | 1088 | // nothing else we can do ask for a key 1089 | request_recovery = KEY; 1090 | vpxlog_dbg(SKIP, "Requested key frame %c:%d,%u\n", command, 1091 | tp->frame_type, seq, R4(tp->timestamp)); 1092 | 1093 | continue; 1094 | } 1095 | 1096 | #endif 1097 | send_packet(&x, &vpx_socket, address); 1098 | vpx_net_set_read_timeout(&vpx_socket2, 1); 1099 | 1100 | // check to see if we have a frame in our packet store. 1101 | if (get_frame() == 0) { 1102 | // do we have room in our packet store for a frame 1103 | if (x.add_ptr - x.send_ptr < MAX_PACKETS_PER_FRAME) { 1104 | int frame_type; 1105 | long long time_in_nano_seconds = (long long) (buffer_time * 10000000.000 1106 | + .5); 1107 | unsigned int rtptime = (unsigned int) ((long long) (buffer_time 1108 | * 1000000.000) & 0xffffffff); 1109 | double fps = 10000000.000 1110 | / (time_in_nano_seconds - last_time_in_nanoseconds); 1111 | 1112 | //printf("%14.4g\n",fps); 1113 | const vpx_codec_cx_pkt_t *pkt; 1114 | vpx_codec_iter_t iter = NULL; 1115 | flags = recovery_flags[request_recovery]; 1116 | 1117 | vpx_codec_encode(&encoder, &raw, time_in_nano_seconds, 30000000, flags, 1118 | VPX_DL_REALTIME); 1119 | ctx_exit_on_error(&encoder, "Failed to encode frame"); 1120 | 1121 | while ((pkt = vpx_codec_get_cx_data(&encoder, &iter))) { 1122 | if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 1123 | last_time_in_nanoseconds = time_in_nano_seconds; 1124 | 1125 | frame_type = request_recovery; 1126 | 1127 | // a recovery frame was requested move sendptr to current ptr, so 1128 | // that we don't spend datarate sending packets that won't be used. 1129 | if (request_recovery) { 1130 | x.send_ptr = x.add_ptr; 1131 | request_recovery = 0; 1132 | } 1133 | 1134 | if (frame_type == GOLD || frame_type == KEY) 1135 | gold_recovery_seq = x.seq; 1136 | 1137 | if (frame_type == ALTREF || frame_type == KEY) 1138 | altref_recovery_seq = x.seq; 1139 | 1140 | packetize(&x, rtptime, (unsigned char *) pkt->data.frame.buf, 1141 | pkt->data.frame.sz, frame_type); 1142 | 1143 | vpxlog_dbg(FRAME, "Frame %d %d %u %10.4g %d\n", 1144 | R2(x.packet[x.send_ptr].seq), pkt->data.frame.sz, 1145 | R4(x.packet[x.send_ptr].timestamp), fps, 1146 | gold_recovery_seq); 1147 | #ifdef WRITEFILE 1148 | fwrite(&pkt->data.frame.sz, 4, 1, out_file); 1149 | fwrite(pkt->data.frame.buf, pkt->data.frame.sz, 1, out_file); 1150 | #endif 1151 | i++; 1152 | } 1153 | } 1154 | } 1155 | 1156 | buffer_has_frame = false; 1157 | } 1158 | 1159 | } 1160 | 1161 | #ifdef WINDOWS 1162 | // graph->Abort(); 1163 | CoUninitialize(); 1164 | #endif 1165 | 1166 | vpx_net_close(&vpx_socket2); 1167 | vpx_net_close(&vpx_socket); 1168 | vpx_net_destroy(); 1169 | 1170 | #ifdef WRITEFILE 1171 | fclose(out_file); 1172 | #endif 1173 | 1174 | vpx_codec_destroy(&encoder); 1175 | vpx_img_free(&raw); 1176 | return 0; 1177 | } 1178 | -------------------------------------------------------------------------------- /receivedecompressandplay.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | /* 12 | * This example illustrates using VP8 in a packet loss scenario by xmitting 13 | * video over UDP with Forward Error Correction, Packet Resend, and 14 | * some Unique VP8 functionality. 15 | * 16 | */ 17 | 18 | #include "tctypes.h" 19 | #include "vpx_network.h" 20 | #include 21 | #include //for tolower 22 | #include 23 | 24 | extern "C" { 25 | #include "rtp.h" 26 | #define VPX_CODEC_DISABLE_COMPAT 1 27 | #include "vpx/vpx_decoder.h" 28 | #include "vpx/vp8dx.h" 29 | } 30 | 31 | typedef struct { 32 | unsigned int seq; 33 | unsigned short arrival; 34 | unsigned int retry; 35 | unsigned short age; 36 | unsigned int received; 37 | unsigned int given_up; 38 | } SKIPS; 39 | 40 | #define SSRC 411 41 | #define SS 256 42 | #define SSM (SS-1) 43 | #define PS 2048 44 | #define PSM (PS-1) 45 | #define MAX_NUMERATOR 16 46 | #define HRE(y) if(FAILED(hr=y)) {vpxlog_dbg(ERRORS,#y##":%x\n",hr);}; 47 | 48 | unsigned short first_seq_ever = 0; 49 | unsigned int lag_In_milli_seconds = 0; 50 | unsigned int first_time_stamp_ever = 0; 51 | unsigned int time_of_first_display = 0; 52 | int given_up = 0; 53 | int givenup_skip = 0; 54 | int display_width = 640; 55 | int display_height = 480; 56 | int capture_frame_rate = 30; 57 | int video_bitrate = 300; 58 | int fec_numerator = 6; 59 | int fec_denominator = 5; 60 | int skip_timeout = 800; 61 | int retry_interval = 50; 62 | unsigned short retry_count = 12; 63 | int drop_simulation = 0; 64 | unsigned short send_port = 1408; 65 | unsigned short recv_port = 1407; 66 | unsigned int quit = 0; 67 | int signalquit = 1; 68 | CODEC video_codec = VPX_VP9; 69 | unsigned char compressed_video_buffer[400000]; 70 | unsigned char output_video_buffer[1280 * 1024 * 3]; 71 | tc8 one_packet[8000]; 72 | 73 | #ifdef WINDOWS 74 | 75 | #include "stdafx.h" 76 | #include 77 | #include 78 | #include // ATL CComPtr 79 | #include 80 | CComPtr direct_draw; 81 | DDCAPS caps; 82 | CComPtr primary_surface, overlay_surface; 83 | CComPtr clipper; 84 | DDOVERLAYFX overlay_fx; 85 | DWORD overlay_flags; 86 | DDSURFACEDESC2 ddsd; 87 | HANDLE thread; 88 | DWORD thread_id; 89 | HWND hwnd; 90 | MSG msg; 91 | WNDCLASS wc; 92 | RECT client_rect; 93 | LRESULT APIENTRY main_wnd_proc(HWND hwnd, UINT msg, UINT parm1, LONG parm2) { 94 | INPUT_RECORD ir; 95 | HANDLE console_input; 96 | unsigned int count; 97 | 98 | switch (msg) { 99 | case WM_DESTROY: 100 | console_input = GetStdHandle(STD_INPUT_HANDLE); 101 | ir.EventType = KEY_EVENT; 102 | ir.Event.KeyEvent.uChar.AsciiChar = 'q'; 103 | WriteConsoleInput(console_input, &ir, 1, (LPDWORD) & count); 104 | PostQuitMessage(0); 105 | break; 106 | case WM_MOVE: 107 | GetWindowRect(hwnd, &client_rect); 108 | DefWindowProc(hwnd, msg, parm1, parm2); 109 | break; 110 | } 111 | 112 | return DefWindowProc(hwnd, msg, parm1, parm2); 113 | 114 | } 115 | char app_name[] = "ReceiveDecompressAndPlay"; 116 | void display_win_main(void *dummy) { 117 | wc.style = CS_BYTEALIGNWINDOW; 118 | wc.lpfnWndProc = main_wnd_proc; 119 | wc.cbClsExtra = 0; 120 | wc.cbWndExtra = 0; 121 | wc.hInstance = 0; 122 | wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); 123 | wc.lpszMenuName = NULL; 124 | wc.lpszClassName = app_name; 125 | RegisterClass(&wc); 126 | 127 | hwnd = CreateWindow(app_name, app_name, 128 | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0, 0, 129 | display_width + 9, display_height + 30, NULL, NULL, 0, 130 | NULL); 131 | 132 | if (hwnd == NULL) 133 | ExitThread(-1); 134 | 135 | while (GetMessage(&(msg), NULL, 0, 0)) { 136 | TranslateMessage(&msg); 137 | DispatchMessage(&msg); 138 | } 139 | 140 | } 141 | void setup_surface(void) { 142 | HRESULT hr; 143 | thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) display_win_main, 144 | (LPVOID) NULL, 0, &thread_id); 145 | 146 | HRE(DirectDrawCreateEx(0, (void ** )&direct_draw, IID_IDirectDraw7, 0)); 147 | ZeroMemory(&caps, sizeof(caps)); 148 | caps.dwSize = sizeof(caps); 149 | HRE(direct_draw->GetCaps(&caps, 0)); 150 | HRE(direct_draw->SetCooperativeLevel(0, DDSCL_NORMAL)); 151 | 152 | // Create the primary surface 153 | DDSURFACEDESC2 ddsd; 154 | ZeroMemory(&ddsd, sizeof(ddsd)); 155 | ddsd.dwSize = sizeof(ddsd); 156 | ddsd.dwFlags = DDSD_CAPS; 157 | ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; 158 | HRE(direct_draw->CreateSurface(&ddsd, &primary_surface, 0)); 159 | 160 | direct_draw->CreateClipper(0, &clipper, NULL); 161 | clipper->SetHWnd(0, hwnd); 162 | primary_surface->SetClipper(clipper); 163 | 164 | // Setup the overlay surface's attributes in the surface descriptor 165 | ZeroMemory(&ddsd, sizeof(ddsd)); 166 | ddsd.dwSize = sizeof(ddsd); 167 | ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDPF_YUV 168 | | DDSD_PIXELFORMAT; 169 | ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; 170 | ddsd.dwWidth = display_width; 171 | ddsd.dwHeight = display_height; 172 | ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); 173 | ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC | DDPF_YUV; 174 | ddsd.ddpfPixelFormat.dwFourCC = MAKEFOURCC('Y', 'V', '1', '2'); 175 | 176 | // Attempt to create the surface with theses settings 177 | HRE(direct_draw->CreateSurface(&ddsd, &overlay_surface, 0)); 178 | 179 | } 180 | #define INIT_DXSTRUCT(dxs) { ZeroMemory(&dxs, sizeof(dxs)); dxs.dwSize = sizeof(dxs); } 181 | 182 | int show_frame(vpx_image_t *img) { 183 | DDSURFACEDESC2 ddsd; 184 | INIT_DXSTRUCT(ddsd); 185 | 186 | HRESULT hr = overlay_surface->Lock( 187 | 0, &ddsd, DDLOCK_DONOTWAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, 188 | 0); 189 | 190 | if (SUCCEEDED(hr)) { 191 | unsigned char *out = (unsigned char *) ddsd.lpSurface; 192 | unsigned char *in = img->planes[PLANE_Y]; 193 | 194 | for (DWORD i = 0; i < ddsd.dwHeight; 195 | i++, out += ddsd.lPitch, in += img->stride[PLANE_Y]) { 196 | memcpy(out, in, ddsd.dwWidth); 197 | } 198 | 199 | in = img->planes[PLANE_U]; 200 | 201 | for (DWORD i = 0; i < ddsd.dwHeight / 2; i++, out += ddsd.lPitch / 2, in += 202 | img->stride[PLANE_U]) { 203 | memcpy(out, in, ddsd.dwWidth / 2); 204 | } 205 | 206 | in = img->planes[PLANE_V]; 207 | 208 | for (DWORD i = 0; i < ddsd.dwHeight / 2; i++, out += ddsd.lPitch / 2, in += 209 | img->stride[PLANE_V]) { 210 | memcpy(out, in, ddsd.dwWidth / 2); 211 | } 212 | 213 | HRE(overlay_surface->Unlock(0)); 214 | 215 | RECT dest_rect; 216 | dest_rect.left = 0; 217 | dest_rect.top = 0; 218 | dest_rect.right = display_width; 219 | dest_rect.bottom = display_height; 220 | RECT src_rect = dest_rect; 221 | 222 | primary_surface->Blt(&client_rect, overlay_surface, &src_rect, DDBLT_ASYNC, 223 | NULL); 224 | } else { 225 | switch (hr) { 226 | case DDERR_INVALIDOBJECT: 227 | printf("DDERR_INVALIDOBJECT\n"); 228 | break; 229 | case DDERR_INVALIDPARAMS: 230 | printf("DDERR_INVALIDPARAMS\n"); 231 | break; 232 | case DDERR_OUTOFMEMORY: 233 | printf("DDERR_OUTOFMEMORY\n"); 234 | break; 235 | case DDERR_SURFACEBUSY: 236 | printf("DDERR_SURFACEBUSY\n"); 237 | break; 238 | case DDERR_SURFACELOST: 239 | printf("DDERR_SURFACELOST\n"); 240 | break; 241 | case DDERR_WASSTILLDRAWING: 242 | printf("DDERR_WASSTILLDRAWING\n"); 243 | break; 244 | default: 245 | printf("other\n"); 246 | break; 247 | }; 248 | } 249 | 250 | return 0; 251 | } 252 | void destroy_surface(void) { 253 | } 254 | #else 255 | #define Sleep(X) usleep(1000*X) 256 | extern "C" int _kbhit(void); 257 | #include 258 | #include 259 | #include 260 | #include 261 | 262 | #include 263 | #include 264 | #include 265 | using namespace std; 266 | 267 | struct pt_data { 268 | SDL_Window **ptscreen; 269 | SDL_Event *ptsdlevent; 270 | SDL_Rect *drect; 271 | SDL_mutex *affmutex; 272 | } ptdata; 273 | 274 | static int event_thread(void *data); 275 | 276 | SDL_RendererInfo info; 277 | char driver[128]; 278 | const char *videodevice = NULL; 279 | SDL_Texture *overlay; 280 | SDL_Rect drect; 281 | SDL_Event sdlevent; 282 | SDL_Thread *mythread; 283 | SDL_mutex *affmutex; 284 | SDL_Renderer *renderer; 285 | SDL_Window * pscreen; 286 | int status; 287 | unsigned char *p = NULL; 288 | unsigned char d1[500], d2[500]; 289 | int w, h; 290 | 291 | int setup_surface(void) { 292 | 293 | if (SDL_Init(SDL_INIT_VIDEO) < 0) { 294 | fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError()); 295 | exit(1); 296 | } 297 | 298 | pscreen = SDL_CreateWindow("Receive Decompress and Play", 299 | SDL_WINDOWPOS_UNDEFINED, 300 | SDL_WINDOWPOS_UNDEFINED, 301 | display_width, display_height, 302 | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); 303 | 304 | renderer = SDL_CreateRenderer(pscreen, -1, 0); 305 | 306 | overlay = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, display_width, display_height); 307 | 308 | drect.x = 0; 309 | drect.y = 0; 310 | drect.w = display_width; 311 | drect.h = display_height; 312 | 313 | /* initialize thread data */ 314 | ptdata.ptscreen = &pscreen; 315 | ptdata.ptsdlevent = &sdlevent; 316 | ptdata.drect = &drect; 317 | affmutex = SDL_CreateMutex(); 318 | ptdata.affmutex = affmutex; 319 | mythread = SDL_CreateThread(event_thread, NULL, (void *) &ptdata); 320 | 321 | return 0; 322 | } 323 | ; 324 | int show_frame(vpx_image_t *img) { 325 | SDL_LockMutex(affmutex); 326 | SDL_UpdateYUVTexture(overlay, 327 | NULL, 328 | img->planes[VPX_PLANE_Y], 329 | img->stride[VPX_PLANE_Y], 330 | img->planes[VPX_PLANE_V], 331 | img->stride[VPX_PLANE_V], 332 | img->planes[VPX_PLANE_U], 333 | img->stride[VPX_PLANE_U] 334 | ); 335 | SDL_RenderCopy(renderer, overlay, NULL, NULL); 336 | SDL_RenderPresent(renderer); 337 | SDL_UnlockMutex(affmutex); 338 | return 0; 339 | } 340 | 341 | void destroy_surface(void) { 342 | SDL_WaitThread(mythread, &status); 343 | SDL_DestroyMutex(affmutex); 344 | SDL_DestroyTexture(overlay); 345 | SDL_DestroyRenderer(renderer); 346 | SDL_DestroyWindow(pscreen); 347 | SDL_Quit(); 348 | } 349 | 350 | static int event_thread(void *data) { 351 | struct pt_data *gdata = (struct pt_data *) data; 352 | SDL_Event *sdlevent = gdata->ptsdlevent; 353 | SDL_mutex *affmutex = gdata->affmutex; 354 | 355 | while (signalquit) { 356 | SDL_LockMutex(affmutex); 357 | 358 | while (SDL_PollEvent(sdlevent)) //scan the event queue 359 | { 360 | switch (sdlevent->type) { 361 | case SDL_WINDOWEVENT_RESIZED: 362 | SDL_SetWindowSize(pscreen, 363 | sdlevent->window.data1, 364 | sdlevent->window.data2); 365 | break; 366 | case SDL_KEYUP: 367 | break; 368 | case SDL_KEYDOWN: 369 | 370 | switch (sdlevent->key.keysym.sym) { 371 | case SDLK_a: 372 | break; 373 | case SDLK_s: 374 | break; 375 | case SDLK_z: 376 | break; 377 | case SDLK_x: 378 | break; 379 | default: 380 | break; 381 | } 382 | 383 | break; 384 | case SDL_QUIT: 385 | printf("\nStop asked\n"); 386 | signalquit = 0; 387 | break; 388 | } 389 | } //end if poll 390 | 391 | SDL_UnlockMutex(affmutex); 392 | SDL_Delay(50); 393 | } //end main loop 394 | 395 | return 0; 396 | 397 | } 398 | 399 | #endif 400 | 401 | typedef struct { 402 | unsigned int size; 403 | unsigned int count; 404 | unsigned int add_ptr; 405 | unsigned int max; 406 | unsigned int ssrc; 407 | unsigned short oldest_seq; 408 | SKIPS s[SS]; 409 | unsigned int skip_ptr; 410 | PACKET p[PS]; 411 | unsigned int last_frame_timestamp; 412 | unsigned short last_seq; 413 | 414 | } DEPACKETIZER; 415 | DEPACKETIZER y; 416 | 417 | int create_depacketizer(DEPACKETIZER *x) { 418 | unsigned int sn; 419 | x->size = PACKET_SIZE; 420 | x->max = PS; 421 | x->skip_ptr = 0; 422 | x->count = 0; 423 | x->add_ptr = 0; 424 | x->last_frame_timestamp = 0xffffffff; 425 | x->last_seq = 0xffff; 426 | x->ssrc = SSRC; 427 | 428 | // skip store is initialized to no skips in store 429 | for (sn = 0; sn < SS; sn++) 430 | x->s[sn].received = 1; 431 | 432 | return 0; // SUCCESS 433 | } 434 | int remove_skip(DEPACKETIZER *p, unsigned short seq) { 435 | int i; 436 | unsigned int skip_fill = 0; 437 | 438 | // remove packet from skip store if its there it came out of order... 439 | for (i = 0; i < SS; i++) { 440 | if (seq == p->s[i].seq) { 441 | p->s[i].received = 1; 442 | p->s[i].given_up = 0; 443 | p->s[i].age = 0; 444 | //p->s[i].seq = 0; 445 | vpxlog_dbg(SKIP, "Unskip %d \n", seq); 446 | skip_fill = 1; 447 | break; 448 | } 449 | } 450 | 451 | return skip_fill; 452 | } 453 | int remove_skip_less(DEPACKETIZER *p, unsigned short seq) { 454 | int i; 455 | unsigned int skip_fill = 0; 456 | 457 | // remove packet from skip store if its there it came out of order... 458 | for (i = 0; i < SS; i++) { 459 | if ((unsigned short) (p->s[i].seq - seq) > 32767 && !p->s[i].received) { 460 | p->s[i].received = 1; 461 | p->s[i].given_up = 0; 462 | p->s[i].age = 0; 463 | //p->s[i].seq = 0; 464 | vpxlog_dbg(SKIP, "Unskip less than %d : %d \n", seq, p->s[i].seq); 465 | skip_fill = 1; 466 | } 467 | } 468 | 469 | return skip_fill; 470 | } 471 | int add_skip(DEPACKETIZER *p, unsigned short sn) { 472 | // maybe we need to check if skip store is completely full? 473 | if (!p->s[p->skip_ptr].given_up && !p->s[p->skip_ptr].received) { 474 | // if it is what do we do? 475 | sn += 0; 476 | vpxlog_dbg(REBUILD, "Skip Store filled!!!\n"); 477 | } 478 | 479 | // clear data that might mess us up 480 | p->p[sn & PSM].redundant_count = 0; 481 | p->p[sn & PSM].type = DATAPACKET; 482 | p->p[sn & PSM].size = 0; 483 | p->s[p->skip_ptr].arrival = (unsigned short) (get_time() & 0xffff); 484 | p->s[p->skip_ptr].retry = 0; 485 | p->s[p->skip_ptr].seq = sn; 486 | p->s[p->skip_ptr].age = 0; 487 | p->s[p->skip_ptr].received = 0; 488 | p->s[p->skip_ptr].given_up = 0; 489 | p->skip_ptr = ((p->skip_ptr + 1) & SSM); 490 | return 0; 491 | } 492 | void check_recovery(DEPACKETIZER *p, PACKET *x) { 493 | if (x->frame_type == KEY || x->frame_type == GOLD || 494 | x->frame_type == ALTREF) { 495 | unsigned short seq = x->seq; //p->oldest_seq; 496 | unsigned short lastPossibleSeq = p->oldest_seq; //p->last_seq; 497 | PACKET *tp = &p->p[seq & PSM]; 498 | vpxlog_dbg(REBUILD, "Received keyframe or recovery frame -> %d, %u \n", seq, 499 | p->p[x->seq & PSM].timestamp); 500 | 501 | // if we are on a new frame drop everything older than where we are now. 502 | if (x->new_frame) { 503 | p->oldest_seq = seq; 504 | p->last_frame_timestamp = x->timestamp - 1; 505 | seq--; 506 | remove_skip_less(p, seq); 507 | } 508 | // find first non dropped packet prior to now. 509 | else 510 | while (seq != lastPossibleSeq) { 511 | tp = &p->p[seq & PSM]; 512 | 513 | // new timestamp that isn't empty 514 | if (tp->size != 0 && tp->timestamp != x->timestamp && tp->seq == seq) { 515 | remove_skip_less(p, seq); 516 | break; 517 | } 518 | 519 | seq--; 520 | } 521 | 522 | given_up = 0; 523 | } 524 | } 525 | double bits = 0; 526 | unsigned short last = 0; 527 | 528 | int read_packet(DEPACKETIZER *p, tc8 *data, unsigned int size) { 529 | PACKET *x = (PACKET *) data; 530 | unsigned int skip_fill = 0; 531 | x->seq = R2(x->seq); 532 | x->timestamp = R4(x->timestamp); 533 | 534 | // wrong ssrc exit 535 | if (p->ssrc != x->ssrc) 536 | return 0; 537 | 538 | // already received the packet (ignore this one) 539 | if (p->p[x->seq & PSM].seq == x->seq && p->p[x->seq & PSM].size) 540 | return 0; 541 | 542 | // on the first received packet record first time ever numbers 543 | if (!first_time_stamp_ever) { 544 | first_time_stamp_ever = x->timestamp; 545 | first_seq_ever = x->seq; 546 | p->oldest_seq = x->seq; 547 | p->last_seq = p->oldest_seq - 1; 548 | vpxlog_dbg(REBUILD, "Received First TimeStamp ever! -> %d, %u new=%d\n", 549 | x->seq, x->timestamp, x->new_frame); 550 | 551 | if (x->new_frame != 1) { 552 | add_skip(p, x->seq - 1); 553 | p->oldest_seq = x->seq - 1; 554 | vpxlog_dbg(REBUILD, "First packet not start of new frame! -> %d, \n", 555 | x->seq - 1); 556 | } 557 | } 558 | 559 | // if we are on the first frame ever and there's an older 560 | if (first_time_stamp_ever == x->timestamp && first_seq_ever > x->seq) { 561 | first_seq_ever = x->seq; 562 | p->oldest_seq = x->seq; 563 | 564 | if (x->new_frame == 1) { 565 | first_time_stamp_ever = x->timestamp - 1; 566 | } else { 567 | add_skip(p, x->seq - 1); 568 | p->oldest_seq = x->seq - 1; 569 | vpxlog_dbg(REBUILD, "Old seq around! -> %d, \n", x->seq - 1); 570 | } 571 | } 572 | 573 | // toss the packet if its for a frame we've already thrown out or displayed 574 | // maybe roll over is an issue we need to address 575 | if (x->timestamp < p->last_frame_timestamp + 1) { 576 | vpxlog_dbg(DISCARD, "Tossing old seq :%d \n", x->seq); 577 | 578 | // make sure that if we toss our oldest seq we've seen we update 579 | if (x->seq - p->oldest_seq > 0 && x->seq - p->oldest_seq < 32768) { 580 | p->oldest_seq = x->seq + 1; 581 | remove_skip_less(p, p->oldest_seq); 582 | } 583 | 584 | return 0; 585 | } 586 | 587 | skip_fill = remove_skip(p, x->seq); 588 | 589 | // this clears the case that we rebuild a packet after we requested a resend 590 | if (!skip_fill && p->last_seq - x->seq > 0 && p->last_seq - x->seq < 32768) 591 | skip_fill = 1; 592 | 593 | // copy to the packet store 594 | x->size = size - PACKET_HEADER_SIZE; 595 | 596 | if (x->size < PACKET_SIZE) 597 | memset(x->data + x->size, 0, PACKET_SIZE - x->size); 598 | 599 | p->p[x->seq & PSM] = *x; 600 | 601 | vpxlog_dbg(LOG_PACKET, "Received Packet %d, %u : new: %d, " 602 | "frame type: %d given_up: %d oldest: %d \n", 603 | x->seq, p->p[x->seq & PSM].timestamp, x->new_frame, x->frame_type, 604 | given_up, p->oldest_seq); 605 | 606 | // if we get a key frame or recovery frame set this as new frame 607 | check_recovery(p, x); 608 | 609 | // do we have a skip 610 | if (!skip_fill && x->seq != (unsigned short) (p->last_seq + 1) 611 | && x->seq != p->last_seq) { 612 | unsigned short sn; 613 | 614 | // add to skip store 615 | for (sn = p->last_seq + 1; sn != x->seq; sn++) { 616 | vpxlog_dbg(SKIP, "Skipped Packet %d\n", sn); 617 | add_skip(p, sn); 618 | } 619 | } 620 | 621 | if (!skip_fill) 622 | p->last_seq = x->seq; 623 | 624 | return 0; 625 | } 626 | 627 | int rebuild_packet(DEPACKETIZER *p, unsigned short seq) { 628 | unsigned short seqp, seqj; 629 | long long *in[MAX_NUMERATOR]; 630 | long long *out = (long long *) p->p[seq & PSM].data; 631 | unsigned int i, j = 0; 632 | unsigned int redundant_count = 0; 633 | PACKET *pp = &p->p[(seq - 1) & PSM]; 634 | PACKET *np = &p->p[(seq + 1) & PSM]; 635 | 636 | // if last packet has type count 1 we don't need this one its type! 637 | // don't bother rebuilding 638 | if (pp->redundant_count == 1) { 639 | p->p[seq & PSM].type = XORPACKET; 640 | p->p[seq & PSM].size = 0; 641 | 642 | if (seq == p->oldest_seq) 643 | p->oldest_seq++; 644 | 645 | return -1; 646 | } 647 | 648 | // if 1 ago is empty, check 2 ago in case we lost redundant packet 649 | if (p->p[(seq - 2) & PSM].redundant_count == 1) 650 | pp = &p->p[(seq - 2) & PSM]; 651 | 652 | // no point doing this frame before the last one is ready 653 | if (pp->timestamp < p->last_frame_timestamp) 654 | return -1; 655 | 656 | p->p[seq & PSM].type = DATAPACKET; 657 | 658 | // search through subsequent packets for the redundant packet 659 | for (seqp = seq + 1; seqp != (unsigned short) (seq + MAX_NUMERATOR); seqp++) { 660 | // found redundant packet filled in ? 661 | if (p->p[seqp & PSM].type && p->p[seqp & PSM].size) { 662 | redundant_count = p->p[seqp & PSM].redundant_count; 663 | 664 | // if initiate call this seq isn't covered. 665 | if (redundant_count < (unsigned short) (seqp - seq)) { 666 | return -1; 667 | } 668 | 669 | break; 670 | } 671 | } 672 | 673 | // go back through the packets and set up input pointers 674 | for (seqj = seqp; seqj != seqp - 1 - redundant_count; seqj--) { 675 | // set up pointer to data for each seq in recovery frame 676 | if (seqj != seq) { 677 | // if its missing or the seq is wrong return a failure. 678 | if (p->p[seqj & PSM].size == 0 || p->p[seqj & PSM].seq != seqj) { 679 | return -1; 680 | } 681 | 682 | in[j++] = (long long *) p->p[seqj & PSM].data; 683 | } 684 | } 685 | 686 | // nothing was listed as type? 687 | if (!redundant_count) { 688 | return -1; 689 | } 690 | 691 | // go through a full packet's worth of data. 692 | for (j = 0; j < (sizeof(long long) - 1 + PACKET_SIZE) / sizeof(long long); 693 | j++) { 694 | // start with the most recent packet 695 | *out = *(in[0]); 696 | 697 | // xor all the older packets with out 698 | for (i = 1; i < redundant_count; i++) { 699 | *out ^= *(in[i]); 700 | in[i]++; 701 | } 702 | 703 | out++; 704 | in[0]++; 705 | } 706 | 707 | // real data filled to the brim with data. 708 | p->p[seq & PSM].seq = seq; 709 | p->p[seq & PSM].type = DATAPACKET; 710 | p->p[seq & PSM].size = PACKET_SIZE; 711 | p->p[seq & PSM].timestamp = pp->timestamp; 712 | p->p[seq & PSM].new_frame = 0; 713 | p->p[seq & PSM].end_frame = 0; 714 | p->p[seq & PSM].frame_type = pp->frame_type; 715 | 716 | // if np is type and end_frame this packet ends frame 717 | if (np->end_frame && np->type) 718 | p->p[seq & PSM].end_frame = 1; 719 | 720 | // last packet ends frame 721 | if (pp->end_frame) { 722 | // if next packet is a new frame we have to fabricate a frame.. 723 | if (np->new_frame) { 724 | p->p[seq & PSM].timestamp = (pp->timestamp + np->timestamp) / 2; 725 | p->p[seq & PSM].new_frame = 1; 726 | p->p[seq & PSM].end_frame = 1; 727 | } else { 728 | // this must be the frame start 729 | p->p[seq & PSM].frame_type = np->frame_type; 730 | p->p[seq & PSM].timestamp = np->timestamp; 731 | p->p[seq & PSM].new_frame = 1; 732 | } 733 | } 734 | 735 | // logging what packets we used to rebuild 736 | if (LOG_MASK & REBUILD) { 737 | unsigned short last = seqj + redundant_count + 2; 738 | seqj++; 739 | vpxlog_dbg(REBUILD, "Rebuilt Lost Sequence :%d, %u from: ", seq, 740 | p->p[seq & PSM].timestamp); 741 | 742 | for (; seqj != last; seqj++) 743 | if (seq != seqj) 744 | vpxlog_dbg_no_head(REBUILD, "%d, ", p->p[seqj & PSM].seq); 745 | 746 | vpxlog_dbg_no_head(REBUILD, "\n"); 747 | } 748 | remove_skip(p, seq); 749 | 750 | check_recovery(p, &p->p[seq & PSM]); 751 | return 0; 752 | } 753 | 754 | int frame_ready(DEPACKETIZER *p) { 755 | // check if we have a whole frame. 756 | unsigned short seq = p->oldest_seq; // f->first_seq; 757 | unsigned short last_possible_seq = p->last_seq; 758 | PACKET *tp = &p->p[seq & PSM]; 759 | 760 | unsigned int timestamp = p->p[seq & PSM].timestamp; 761 | 762 | if (timestamp < p->last_frame_timestamp + 1) { 763 | vpxlog_dbg(FRAME, "Trying to play an old frame:%d, timestamp :%u , " 764 | "last Time :%u \n", 765 | seq, timestamp, p->last_frame_timestamp); 766 | return 0; 767 | } 768 | 769 | // seems like this should be unnecessary??? 770 | while (timestamp && p->p[seq & PSM].timestamp == timestamp 771 | && !p->p[seq & PSM].new_frame) 772 | seq--; 773 | 774 | p->oldest_seq = seq; 775 | remove_skip_less(p, p->oldest_seq); 776 | 777 | // first seq not a new frame. Frames not ready. 778 | if (!p->p[seq & PSM].new_frame) { 779 | if (p->p[(seq - 1) & PSM].type == XORPACKET) 780 | p->p[seq & PSM].new_frame = 1; 781 | else 782 | return 0; 783 | } 784 | 785 | // loop through all frames and see if every packet between start and 786 | // end is present or we are missing type frames. 787 | while (seq != last_possible_seq) { 788 | tp = &p->p[seq & PSM]; 789 | 790 | // timestamp needs to differ and the packet has to have data 791 | if (tp->timestamp != timestamp || tp->size == 0) { 792 | // here we have a whole frame but end frame marker not set properly 793 | if (tp->new_frame && tp->size > 0) { 794 | p->p[(seq - 1) & PSM].end_frame = 1; 795 | return 1; 796 | } 797 | 798 | // if missing packet is not type frame is not ready. 799 | if (p->p[(seq - 1) & PSM].redundant_count != 1) 800 | return 0; 801 | 802 | // make sure frame is marked type 803 | tp->type = XORPACKET; 804 | } else if (tp->end_frame) 805 | return 1; 806 | 807 | seq++; 808 | } 809 | 810 | return 0; 811 | } 812 | int get_frame(DEPACKETIZER *p, unsigned char *data, int size, 813 | unsigned int *outsize, unsigned int *timestamp) { 814 | *outsize = 0; 815 | 816 | // check if we have a whole frame. 817 | if (frame_ready(p)) { 818 | unsigned short seq = p->oldest_seq; 819 | unsigned short last_possible_seq = p->last_seq; 820 | *timestamp = p->p[seq & PSM].timestamp; 821 | 822 | // build a frame from the packets we have. 823 | while (seq != last_possible_seq) { 824 | PACKET *tp = &p->p[seq & PSM]; 825 | 826 | // timestamp needs to match and size must be > 0 827 | if (tp->timestamp == *timestamp && tp->size > 0 828 | && tp->type == DATAPACKET) { 829 | memcpy(data, tp->data, tp->size); 830 | data += tp->size; 831 | *outsize += tp->size; 832 | tp->size = 0; 833 | 834 | if (tp->end_frame) 835 | break; 836 | } 837 | 838 | // its a skip clear from skip remove it 839 | if (tp->size == 0) { 840 | remove_skip(p, seq); 841 | } 842 | 843 | seq++; 844 | } 845 | 846 | // if we have a xorpacket frame at the end of our frame throw it out 847 | if (p->p[(seq + 1) & PSM].timestamp == *timestamp 848 | && p->p[(seq + 1) & PSM].type == XORPACKET) { 849 | seq++; 850 | } 851 | 852 | p->last_frame_timestamp = *timestamp; 853 | p->oldest_seq = seq + 1; 854 | 855 | return 1; 856 | } 857 | 858 | return 0; 859 | } 860 | 861 | int age_skip_store(DEPACKETIZER *p, struct vpxsocket *vpx_sock, 862 | union vpx_sockaddr_x *address) { 863 | unsigned int request_count = 0; 864 | unsigned int i; 865 | unsigned short now = (unsigned short) (get_time() & 0xffff); 866 | 867 | if (given_up) { 868 | // we've given up on a frame do nothing else until we get a recovery frame. 869 | unsigned short time_to_retry = 0; 870 | unsigned short seq = p->s[givenup_skip].seq; 871 | 872 | if (p->s[givenup_skip].arrival <= now) 873 | p->s[givenup_skip].age = now - p->s[givenup_skip].arrival; 874 | else 875 | p->s[givenup_skip].age = (unsigned short) ((unsigned int) (0xffff + now) 876 | - p->s[givenup_skip].arrival); 877 | 878 | time_to_retry = (p->s[givenup_skip].age 879 | > (p->s[givenup_skip].retry * retry_interval)); 880 | 881 | if (time_to_retry && ((rand() & 1023) >= drop_simulation)) { 882 | // Tell the sender we want to give up 883 | int bytes_sent; 884 | tc8 buffer[40]; 885 | buffer[0] = 'g'; 886 | buffer[1] = seq & 0x00ff; 887 | buffer[2] = (seq & 0xff00) >> 8; 888 | vpx_net_sendto(vpx_sock, buffer, 3, &bytes_sent, *address); 889 | vpxlog_dbg(DISCARD, "Give up forever on sequence %d now %d :age :%d" 890 | " retry:%d \n", 891 | seq, now, p->s[givenup_skip].age, p->s[givenup_skip].retry); 892 | p->s[givenup_skip].retry++; 893 | } 894 | 895 | return 0; 896 | } 897 | 898 | for (i = 0; i < SS; i++) { 899 | if (!p->s[i].received && !p->s[i].given_up) { 900 | request_count++; 901 | } 902 | } 903 | 904 | // go through the skip store 905 | for (i = 0; i < SS; i++) { 906 | // if this skip is still in play 907 | if (!p->s[i].received && !p->s[i].given_up) { 908 | unsigned short seq = p->s[i].seq; 909 | unsigned short time_to_retry = 0; 910 | unsigned int is_redundant = (p->p[(p->s[i].seq - 1) & PSM].redundant_count 911 | == 1); 912 | 913 | // calculate the age of the skip including wrap around 914 | if (p->s[i].arrival <= now) 915 | p->s[i].age = now - p->s[i].arrival; 916 | else 917 | p->s[i].age = (unsigned short) ((unsigned int) (0xffff + now) 918 | - p->s[i].arrival); 919 | 920 | time_to_retry = (p->s[i].age > (p->s[i].retry * retry_interval)); 921 | 922 | // if its redundant don't bother rebuilding requesting it again. 923 | if (is_redundant) { 924 | p->s[i].given_up = 1; 925 | p->p[p->s[i].seq & PSM].size = 0; 926 | 927 | vpxlog_dbg(LOG_PACKET, "Lost redundant packet %d, ignoring \n", seq); 928 | 929 | } 930 | // try and rebuild from recovery packets 931 | else if (rebuild_packet(p, seq) == 0) { 932 | p->s[i].received = 1; 933 | p->s[i].age = 0; 934 | } 935 | // time to give up we wasted enough time 936 | else if (time_to_retry 937 | && (p->s[i].age > skip_timeout || request_count > retry_count)) { 938 | given_up = 1; 939 | givenup_skip = i; 940 | vpxlog_dbg(LOG_PACKET, "Giving up: %d age:%d request_count:%d\n", seq, 941 | p->s[i].age, request_count); 942 | break; 943 | } 944 | // request a resend 945 | else if (time_to_retry && ((rand() & 1023) >= drop_simulation)) { 946 | int bytes_sent; 947 | tc8 buffer[40]; 948 | buffer[0] = 'r'; 949 | buffer[1] = seq & 0x00ff; 950 | buffer[2] = (seq & 0xff00) >> 8; 951 | vpx_net_sendto(vpx_sock, buffer, 3, &bytes_sent, *address); 952 | vpxlog_dbg(DISCARD, "Lost %d, skip: %d, Requesting Resend %d,%d \n", 953 | seq, i, p->s[i].age, (p->s[i].retry * retry_interval)); 954 | p->s[i].retry++; 955 | } 956 | } 957 | 958 | // If we're giving up on this and its the oldest increase the oldest seq. 959 | if (p->oldest_seq == p->s[i].seq && p->s[i].given_up) { 960 | p->oldest_seq++; 961 | } 962 | } 963 | 964 | return 0; 965 | } 966 | #define SHOW_WINDOW 1 967 | //#define DEBUG_FILES 1 968 | #ifdef DEBUG_FILES 969 | void debug_frame(FILE *outFile, vpx_image_t *img) { 970 | unsigned char *in = img->planes[VPX_PLANE_Y]; 971 | 972 | for (int i = 0; i < display_height; i++, in += img->stride[VPX_PLANE_Y]) { 973 | fwrite(in, display_width, 1, outFile); 974 | } 975 | 976 | in = img->planes[VPX_PLANE_U]; 977 | 978 | for (int i = 0; i < display_height / 2; i++, in += img->stride[VPX_PLANE_U]) { 979 | fwrite(in, display_width / 2, 1, outFile); 980 | } 981 | 982 | in = img->planes[VPX_PLANE_V]; 983 | 984 | for (int i = 0; i < display_height / 2; i++, in += img->stride[VPX_PLANE_V]) { 985 | fwrite(in, display_width / 2, 1, outFile); 986 | } 987 | } 988 | #endif 989 | 990 | int main(int argc, char *argv[]) { 991 | printf("ReceiveDecompressAndPlay (-? for help) \n"); 992 | 993 | for (int arg = 0; arg < argc; arg++) { 994 | if (argv[arg][0] == '-') { 995 | switch (argv[arg][1]) { 996 | case '8': 997 | video_codec = VPX_VP8; 998 | break; 999 | case '9': 1000 | video_codec = VPX_VP9; 1001 | break; 1002 | case 'w': 1003 | case 'W': 1004 | display_width = atoi(argv[++arg]); 1005 | break; 1006 | case 'h': 1007 | case 'H': 1008 | display_height = atoi(argv[++arg]); 1009 | break; 1010 | case 'f': 1011 | case 'F': 1012 | capture_frame_rate = atoi(argv[++arg]); 1013 | break; 1014 | case 'b': 1015 | case 'B': 1016 | video_bitrate = atoi(argv[++arg]); 1017 | break; 1018 | case 'n': 1019 | case 'N': 1020 | fec_numerator = atoi(argv[++arg]); 1021 | break; 1022 | case 'd': 1023 | case 'D': 1024 | fec_denominator = atoi(argv[++arg]); 1025 | break; 1026 | case 't': 1027 | case 'T': 1028 | skip_timeout = atoi(argv[++arg]); 1029 | break; 1030 | case 'i': 1031 | case 'I': 1032 | retry_interval = atoi(argv[++arg]); 1033 | break; 1034 | case 'c': 1035 | case 'C': 1036 | retry_count = atoi(argv[++arg]); 1037 | break; 1038 | case 'l': 1039 | case 'L': 1040 | drop_simulation = atoi(argv[++arg]); 1041 | break; 1042 | case 's': 1043 | case 'S': 1044 | send_port = atoi(argv[++arg]); 1045 | break; 1046 | case 'r': 1047 | case 'R': 1048 | recv_port = atoi(argv[++arg]); 1049 | break; 1050 | default: 1051 | printf( 1052 | "ReceiveDecompressAndPlay: \n" 1053 | "========================: \n" 1054 | "Receives, decompresses and plays video received from the" 1055 | " GrabCompressAndSend sample.\n\n" 1056 | "-w [640] request capture width \n" 1057 | "-h [480] request capture height \n" 1058 | "-f [30] request capture frame rate\n" 1059 | "-b [300] video_bitrate = ato\n" 1060 | "-n [6] fec_numerator ( redundancy numerator)\n" 1061 | "-d [5] fec_denominator ( redundancy denominator) \n" 1062 | " 6/5 means 1 xor packet for every 5 packets, \n" 1063 | " 4/1 means 3 duplicate packets for every packet\n" 1064 | "-t [800] ms before giving up and requesting recovery \n" 1065 | "-i [50] ms between attempts at a packet resend\n" 1066 | "-c [12] number of lost packets before requesting recovery \n" 1067 | "-l [0] packets to lose out of every 1000 \n" 1068 | "-s [1408] port to send requests to\n" 1069 | "-r [1407] port to receive requests on. \n" 1070 | "\n"); 1071 | exit(0); 1072 | break; 1073 | } 1074 | } 1075 | } 1076 | 1077 | vpxlog_dbg(FRAME,"%dx%d %dfps, %dkbps, %d/%dFEC,%d skip, %d retry interval," 1078 | "%d count, %d drop simulation \n", 1079 | display_width, display_height, capture_frame_rate, video_bitrate, 1080 | fec_numerator, fec_denominator, skip_timeout, retry_interval, 1081 | retry_count, drop_simulation); 1082 | 1083 | struct vpxsocket vpx_sock, vpx_sock2; 1084 | union vpx_sockaddr_x address, address2; 1085 | 1086 | TCRV rc; 1087 | tc32 bytes_read; 1088 | 1089 | #ifdef DEBUG_FILES 1090 | FILE *f = fopen("out2.rtp", "wb"); 1091 | char fn[512]; 1092 | sprintf(fn, "decoded_%dx%d", display_width, display_height); 1093 | FILE *out_file = fopen(fn, "wb"); 1094 | FILE *vpx_file = fopen("decode.vpx", "wb"); 1095 | #endif 1096 | 1097 | int responded = 0; 1098 | 1099 | vpx_codec_ctx_t decoder; 1100 | uint8_t *buf = NULL; 1101 | vpx_codec_dec_cfg_t cfg = {0}; 1102 | int dec_flags = VPX_CODEC_USE_POSTPROC; 1103 | 1104 | 1105 | if (video_codec == VPX_VP8) { 1106 | printf("VP8 \n"); 1107 | vpx_codec_dec_init(&decoder, &vpx_codec_vp8_dx_algo, &cfg, dec_flags); 1108 | } else { 1109 | printf("VP9 \n"); 1110 | vpx_codec_dec_init(&decoder, &vpx_codec_vp9_dx_algo, &cfg, dec_flags); 1111 | } 1112 | 1113 | buf = (uint8_t *) malloc(display_width * display_height * 3 / 2); 1114 | 1115 | /* Config post processing settings for decoder */ 1116 | //ppcfg.post_proc_flag = VP8_DEMACROBLOCK | VP8_DEBLOCK; 1117 | //ppcfg.deblocking_level = 4; 1118 | //ppcfg.noise_level = 44; 1119 | //vpx_codec_control(&decoder, VP8_SET_POSTPROC, &ppcfg); 1120 | 1121 | create_depacketizer(&y); 1122 | 1123 | vpx_net_init(); 1124 | 1125 | if (TC_OK != vpx_net_open(&vpx_sock, vpx_IPv4, vpx_UDP)) 1126 | return -1; 1127 | 1128 | vpx_net_set_read_timeout(&vpx_sock, 20); 1129 | vpx_net_bind(&vpx_sock, 0, recv_port); 1130 | 1131 | if (TC_OK != vpx_net_open(&vpx_sock2, vpx_IPv4, vpx_UDP)) 1132 | return -1; 1133 | 1134 | int bytes_sent; 1135 | 1136 | while (!_kbhit()) { 1137 | char initPacket[PACKET_SIZE]; 1138 | sprintf(initPacket, "configuration %d %d %d %d %d %d ", display_width, 1139 | display_height, capture_frame_rate, video_bitrate, fec_numerator, 1140 | fec_denominator); 1141 | rc = vpx_net_recvfrom(&vpx_sock, one_packet, sizeof(one_packet), 1142 | &bytes_read, &address); 1143 | 1144 | if (rc != TC_OK && rc != TC_WOULDBLOCK && rc != TC_TIMEDOUT) 1145 | vpxlog_dbg(DISCARD, "error\n"); 1146 | 1147 | if (bytes_read == -1) 1148 | bytes_read = 0; 1149 | 1150 | if (bytes_read) { 1151 | if (!responded) { 1152 | char add[400]; 1153 | sprintf(add, "%d.%d.%d.%d", 1154 | ((unsigned char *) &address.sa_in.sin_addr)[0], 1155 | ((unsigned char *) &address.sa_in.sin_addr)[1], 1156 | ((unsigned char *) &address.sa_in.sin_addr)[2], 1157 | ((unsigned char *) &address.sa_in.sin_addr)[3]); 1158 | 1159 | vpxlog_dbg(LOG_PACKET, "Address of Sender : %s \n", add); 1160 | vpx_net_get_addr_info(add, send_port, vpx_IPv4, vpx_UDP, &address2); 1161 | responded = 1; 1162 | } 1163 | 1164 | if (strncmp(one_packet, "initiate call", PACKET_SIZE) == 0) { 1165 | rc = vpx_net_sendto(&vpx_sock2, (tc8 *) &initPacket, PACKET_SIZE, 1166 | &bytes_sent, address2); 1167 | } 1168 | 1169 | if (strncmp(one_packet, "confirmed", PACKET_SIZE) == 0) { 1170 | rc = vpx_net_sendto(&vpx_sock2, (tc8 *) &initPacket, PACKET_SIZE, 1171 | &bytes_sent, address2); 1172 | break; 1173 | } 1174 | } 1175 | 1176 | } 1177 | #ifdef SHOW_WINDOW 1178 | setup_surface(); 1179 | #endif 1180 | 1181 | unsigned int frames_shown = 0; 1182 | /* Message loop for display window's thread */ 1183 | while (!_kbhit() && signalquit) { 1184 | rc = vpx_net_recvfrom(&vpx_sock, one_packet, sizeof(one_packet), 1185 | &bytes_read, &address); 1186 | 1187 | if (rc != TC_OK && rc != TC_WOULDBLOCK && rc != TC_TIMEDOUT) 1188 | vpxlog_dbg(DISCARD, "error %d\n", rc); 1189 | 1190 | if (bytes_read == -1) { 1191 | // vpxlog_dbg("-1 bytes_read \n"); 1192 | bytes_read = 0; 1193 | } 1194 | 1195 | if (bytes_read) { 1196 | unsigned int timestamp; 1197 | unsigned int size; 1198 | 1199 | // random drops 1200 | if ((rand() & 1023) > drop_simulation) { 1201 | read_packet(&y, one_packet, bytes_read); 1202 | bits += bytes_read * 8; 1203 | } 1204 | 1205 | while (get_frame(&y, compressed_video_buffer, 1206 | sizeof(compressed_video_buffer), &size, ×tamp)) { 1207 | lag_In_milli_seconds = (unsigned int) ((timestamp 1208 | - first_time_stamp_ever) / 1000.0 1209 | - (get_time() - time_of_first_display)); 1210 | vpxlog_dbg(FRAME, "Received frame %u, Size:%d, Lag: %d \n", timestamp, 1211 | size, lag_In_milli_seconds); 1212 | 1213 | #ifdef DEBUG_FILES 1214 | fwrite(&size, 4, 1, vpx_file); 1215 | fwrite(compressed_video_buffer, size, 1, vpx_file); 1216 | #endif 1217 | 1218 | if (!time_of_first_display) { 1219 | #ifdef WINDOWS 1220 | ShowWindow(hwnd, SW_SHOWNOACTIVATE); 1221 | UpdateWindow(hwnd); 1222 | #endif 1223 | time_of_first_display = get_time(); 1224 | } 1225 | 1226 | vpx_codec_iter_t iter = NULL; 1227 | vpx_image_t *img; 1228 | 1229 | if (vpx_codec_decode(&decoder, compressed_video_buffer, size, 0, 0)) { 1230 | vpxlog_dbg(ERRORS, "Failed to decode frame: %s\n", 1231 | vpx_codec_error(&decoder)); 1232 | return -1; 1233 | } 1234 | 1235 | img = vpx_codec_get_frame(&decoder, &iter); 1236 | #ifdef SHOW_WINDOW 1237 | show_frame(img); 1238 | frames_shown++; 1239 | 1240 | #endif 1241 | #ifdef DEBUG_FILES 1242 | debug_frame(out_file, img); 1243 | #endif 1244 | 1245 | vpxlog_dbg(FRAME, "Played frame timestamp :%u \n", timestamp); 1246 | 1247 | }; 1248 | 1249 | if (!responded) { 1250 | char add[400]; 1251 | sprintf(add, "%d.%d.%d.%d", ((char *) &address.sa_in.sin_addr)[0], 1252 | ((char *) &address.sa_in.sin_addr)[1], 1253 | ((char *) &address.sa_in.sin_addr)[2], 1254 | ((char *) &address.sa_in.sin_addr)[3]); 1255 | 1256 | vpxlog_dbg(LOG_PACKET, "Address of Sender : %s \n", add); 1257 | vpx_net_get_addr_info(add, send_port, vpx_IPv4, vpx_UDP, &address2); 1258 | responded = 1; 1259 | } 1260 | 1261 | #ifdef DEBUG_FILES 1262 | fwrite(one_packet, bytes_read, 1, f); 1263 | #endif 1264 | 1265 | } else 1266 | age_skip_store(&y, &vpx_sock2, &address2); 1267 | 1268 | // Collect some stats 1269 | unsigned short elapsed = (unsigned short) ((get_time() & 0xffff) - last); 1270 | if (bits != 0 && elapsed > 1000) { 1271 | double bitrate = 1.0 * bits / elapsed; 1272 | double framerate = 1000.0 * frames_shown / elapsed; 1273 | bits = 0; 1274 | frames_shown = 0; 1275 | printf("bitrate: %14.4f fps: %14.4f\n", bitrate, framerate); 1276 | last = (unsigned short) (get_time() & 0xffff); 1277 | } 1278 | if (bits == 0) 1279 | last = (unsigned short) (get_time() & 0xffff); 1280 | 1281 | 1282 | } 1283 | vpxlog_dbg(ERRORS, "Exited successfully.\n"); 1284 | 1285 | signalquit = 0; 1286 | 1287 | #ifdef DEBUG_FILES 1288 | fclose(f); 1289 | fclose(out_file); 1290 | fclose(vpx_file); 1291 | #endif 1292 | 1293 | if (vpx_codec_destroy(&decoder)) { 1294 | vpxlog_dbg(DISCARD, "Failed to destroy decoder: %s\n", 1295 | vpx_codec_error(&decoder)); 1296 | return -1; 1297 | } 1298 | 1299 | free(buf); 1300 | 1301 | vpx_net_close(&vpx_sock); 1302 | vpx_net_destroy(); 1303 | destroy_surface(); 1304 | return 0; 1305 | } 1306 | --------------------------------------------------------------------------------